In Ruby, which of proc, Proc.new, lambda and the -> literal create lambdas, and how do you check one?
answer
- two constructors each
- one class for all four
- Proc#lambda? is the check
- lambda needs a literal block
- no block: ArgumentError
basics
~10 slambda { } and ->(x) { } create lambdas; proc { } and Proc.new { } create regular procs. All four return a Proc, so check with Proc#lambda?, which is true only for lambdas.
solid answer
~30 s`lambda { }` and the stabby literal `->(x) { }` create lambdas; `Kernel#proc` and `Proc.new` create regular procs, and so does a captured block. All of them are instances of `Proc`, so `is_a?(Proc)` or `class` cannot tell them apart, but `Proc#lambda?` can: `->(x) { x }.lambda?` is `true`, `proc { |x| x }.lambda?` is `false`. Lambda-ness is fixed at creation and cannot be converted: since Ruby 3.3, `lambda(&some_proc)` with a regular proc raises `ArgumentError` (`the lambda method requires a literal block`), and `proc(&some_lambda)` returns the same lambda unchanged. `proc` and `Proc.new` without a block raise `ArgumentError` too.
code
ruby · 10 linespresence = ->(value) { !value.nil? }
legacy = proc { |value| !value.nil? }
presence.lambda? # => true
legacy.lambda? # => false
presence.class # => Proc
proc(&presence).lambda? # => true, same object returned
lambda(&legacy) # ArgumentError: the lambda method requires a literal block
Proc.new # ArgumentError: tried to create Proc object without a blockgo deeper
Recall the pairs: lambda and -> make lambdas, proc and Proc.new make regular procs, and lambda? tells them apart.
Explain that the kind is a flag on one class, fixed at creation, and what it changes: argument checking and where return goes.
Catch upgrade breakage: lambda(&proc) raising since Ruby 3.3, and blockless Proc.new relying on long-deprecated block capture.
Decide how a library accepts callables: duck-type on call, build its own as lambdas, and check lambda? only where semantics truly matter.
## Four constructors, one class Ruby has one class for packaged blocks of code, `Proc`, and four everyday ways to make one: | Expression | Kind | `lambda?` | |---|---|---| | `proc { \|x\| x }` | regular proc | `false` | | `Proc.new { \|x\| x }` | regular proc | `false` | | `lambda { \|x\| x }` | lambda | `true` | | `->(x) { x }` | lambda | `true` | - **`Kernel#proc`** is documented as equivalent to `Proc.new`. - **`Kernel#lambda`** is equivalent to `Proc.new` except that the result checks the number of arguments it receives. - **`->`** is the lambda literal. Parameters usually go in parentheses before the body: `->(value, field) { ... }`, or `-> { ... }` with none. - A **block captured** with an `&block` parameter is a regular proc as well. The kind decides two behaviours: whether arguments are checked strictly, and whether `return` leaves the callable or its enclosing method. ## Checking the kind with Proc#lambda? Because every one of these objects is a `Proc`, class checks cannot tell them apart: - `->(x) { x }.class` and `proc { |x| x }.class` both return `Proc`. - `is_a?(Proc)` is `true` for both. - `Proc#lambda?` returns `true` for a lambda and `false` for a regular proc. It is the only direct check. When `inspect` prints a lambda, Ruby adds `(lambda)` to the description, which helps when debugging in `irb`. ## Lambda-ness cannot be converted The flag is set when the object is created and stays with it: 1. **`proc(&a_lambda)`** and **`Proc.new(&a_lambda)`** return the lambda itself, and `lambda?` is still `true`. 2. **`lambda(&a_regular_proc)`** raises `ArgumentError` with the message `the lambda method requires a literal block` on Ruby 3.3 and later. Ruby 3.0 to 3.2 returned the regular proc unchanged, warning only under the deprecated warning category, so the call looked like a conversion but did nothing. 3. **`lambda(&:upcase)`** is allowed, because a symbol block is accepted. 4. **Passing a lambda with `&`** to a method does not make it lenient; the method yields into lambda semantics. If you need a lambda, write the lambda where the code is: `->(v) { ... }` or `lambda { |v| ... }` with a literal block. ## Blockless calls On Ruby 4.0, `proc`, `Proc.new` and `lambda` all need a block. `Proc.new` and `proc` without one raise `ArgumentError` with `tried to create Proc object without a block`. Very old code relied on a blockless `proc` inside a method capturing that method's block; Ruby 2.7 deprecated that, and the replacement is an explicit `&block` parameter. ## Picking a constructor In a form library that stores validation rules as callables: - Write rules as **`->(value) { ... }`**. The literal is short and the resulting lambda checks its arguments. - Use **`lambda { |value| ... }`** when a multi-line `do ... end` body reads better; it builds the same kind of object. - Reserve **`proc`** for the rare case where you want block leniency in a stored object. - When accepting callables from users of the library, check `respond_to?(:call)` rather than the class, and consult `lambda?` only if your code truly depends on strict arity.
- What happened to lambda(&some_proc) before Ruby 3.3?From Ruby 3.0 it warned under the deprecated warning category and returned the regular proc unchanged, so the result still had lenient arguments and a method-leaving `return`. Ruby 3.3 made it raise `ArgumentError`, turning the silent non-conversion into an error.
- Does proc(&a_lambda) produce a regular proc?No. When `proc` or `Proc.new` receives an existing `Proc` object of class `Proc` as its block, it returns that object, so the lambda comes back unchanged and `lambda?` stays `true`.
saying these in an interview costs you the question
- Proc.new with a block returns a lambda
- Lambdas are instances of a separate class
- lambda(&some_proc) converts a regular proc into a lambda
- is_a?(Proc) returns false for a lambda
- Proc.new without a block captures the method's block