-
Notifications
You must be signed in to change notification settings - Fork 1
Blocks, Procs and Lambdas
In Ruby syntax, there are 3 basic types of "units of code" i.e. chunks of code that are executed top to bottom when they are invoked.
- The whole Ruby program, i.e. usually the whole contents of a Ruby source file, executed when it is loaded. This definition also applies to any Ruby source files that are loaded (e.g. via the
requiremethod) as part of another Ruby program. - Methods, executed when the method is called
- Blocks, executed when the block is called
A block is a bit like an anonymous method - it's a chunk of code which accepts method-like arguments and returns a value, but it doesn't have a name and is not defined on a class. However, there are some important differences.
Key characteristics of blocks:
- A block is not a Ruby value - it's not an Object, it can't be assigned to a variable, can't be used as an operand for operators, can't be passed to methods as a regular value argument etc. Rather, a block is intrinsically a part of the syntax and mechanics of a method call
- If you wish to treat the block as an object, it is possible to do so - a block can be wrapped in an instance of the Proc class (i.e. a Proc) e.g. via a block formal argument
- A block within a Proc can be invoked by using the Proc's
callmethod
- A block within a Proc can be invoked by using the Proc's
- A Proc can be unwrapped again into a block passed to a method via a block call argument
- A block can be invoked with call arguments the same as a method
- A block can accept formal arguments similar to a method, with some slight differences
- A block has a return value
- A block internally has "lambda" flag, which when set, alters the behaviour of the block slightly:
- A block with lambda flag set accepts formal arguments the same way as a method
- A block with lambda flag set has slightly different semantics for Ruby control transfer statements, such as
return
- A block can be manipulated in the following specific ways (excluding lambda expressions, see below):
- A block is created in a method call, and passed to the called method for it to use, either by specifying a block or a block call argument in the method call
- A method can invoke its passed block with the
yieldstatement - A method can use other Ruby statements which do things with the block, such as
super - A method can wrap its passed block in a Proc by accepting a block formal argument
- A method can call specialized core methods that manipulate the passed block, such as
block_given?which tests for the presence of a block
A Proc is an instance of the Proc class, whose purpose is to wrap a Block inside an object so it can be treated as an object. A Proc is therefore closer to what you might think of as an "anonymous method", especially if its block has the lambda flag set.
A block with lambda flag set is typically created by:
- the
lambdamethod, which accepts a block and returns a Proc with that block and its lambda flag set e.g .lambda { |arg| puts arg } - equivalently, you can use the
->lambda expression syntax e.g.-> (arg) { puts arg }. Technically, this is a 4th type of unit of code possible in the Ruby syntax, however its more useful to think of this as syntax shorthand for thelambdamethod
A "lambda" is a little tricky to define:
- Normally, a "lambda" refers to a Proc created on a block with lambda flag set, however:
- If you create such a Proc e.g. with
lambdaor->and then unwrap it by passing it to a method via a block call argument, is the block thus passed (which has lambda flag set) a lambda? I will say yes, and use the term "lambda" interchangeably for these two concepts. If needed, I'll distinguish them by describing "lambda Procs" and "lambda blocks".
A Ruby Language Reference
Copyright © by Michael Hore, 2016.
Introduction to This Document
Ruby Elements
- Classes and Modules
- Methods
- Blocks, Procs and Lambdas
- Execution Context and Closures
- Variables, Constants and Namespaces
- Types and Literals
- Ruby Expressions
- Operators
Syntax Grammar
Exceptions and Throw
Ruby Sourcefiles and Libraries
Multi Threading
Execution and Lifecycle