If you are not familiar with Ruby then you could be quite scared by multiple articles about lambda , proc , block and different styles of how they could be defined and used. If you are familiar with them you may already know that there is nothing special but something still could be missed, so I will try to make it cleaner and fill some gaps.

How we define our ‘proc’ and ‘lambda’

Proc.new { p 'Hello!' } # => #<Proc:

my_proc = proc { p 'Hello!' } # => #<Proc: my_proc =.new { p 'Hello!' } # => # 0x000055 ...>my_proc{ p 'Hello!' } # => # 0x000055...> lambda { p 'Hello!' } # => #<Proc:

my_lambda = -> { p 'Hello!' } # => #<Proc:0x000055 my_lambda ={ p 'Hello!' } # => # 0x000055... (lambda)>my_lambda ={ p 'Hello!' } # => # ... (lambda)>

You could replace {} with do end and have the same results but with a pretty different look and if you will mix these styles with no reasons then it will be just harder to read and one more way to frighten newcomers. So, if you have multiline definition then do end could be better than {} , while for inline definitions {} is more appropriate, BTW there is no relation between lambda and {} as between Proc and do end .

In which way to construct — Proc.new is just an explicit way of creating new proc as an instance of the Proc class instance and almost never used on practice, so if we need proc then just use proc keyword but even this is a rare case simply because Ruby has a more elegant way of constructing proc and it has name block to which we will return later. What about lambda keyword it’s mostly used when we have a multiline definition with do end , while for inline definitions we have -> {} , but at some project -> {} could be used even for multiline definitions while lambda in conjunction with do end could be avoided at all.

What about invocation:

greeting = "Hello"

my_lambda = -> (name) { "#{greeting} #{name}!" }

my_lambda.call('John') # => 'Hello John!' greeting = "Aloha"

my_lambda.call('John') # => 'Aloha John!'

my_proc.('John') # => 'Aloha Hello!'

my_proc['John'] # => 'Aloha Hello!'

In the same way both proc and lambda scope outer variables, as a result of changing greeting we changed behavior. At the same time, there are few ways of invocation, while .call is the most common and frequently used way, some projects could follow .() style and have:

add = -> (a) { -> (b) { a + b } } add.(1).(2) # => 3

What is the difference between ‘proc’ and ‘lambda’?

You may already noticed from the definition part that lambda is just some kind of Proc but there is a difference in place of receiving arguments and returning a value, while Proc is a special kind of beast, lambda could be simply treated as an anonymous method because it has the same behavior for incoming arguments and return as a regular method defined with def keyword:

greeting = -> (name) { return "Hello #{name}!" }

greeting.call('John') # => Hello John!

greeting.call() # => ArgumentError (wrong number of arguments ...

But why Proc is something special? — Simply because it behaves in a different way in comparison with regular methods, it’s not restricted to arguments and return not just return some value from inside of Proc , it returns value out from scope it’s defined in:

greeting = proc { |name| return "Aloha John!" if name == 'John' }

greeting.call('Bond') # => nil

greeting.call('John') # => LocalJumpError (unexpected return)



def perform(name)

greeting = proc { |name| return "Aloha John!" if name == 'John' }

greeting.call(name)

"Hello #{name}!"

end perform('Bond') # => "Hello Bond!"

perform('John') # => "Aloha John!"

As you can see, greeting returns value right from perform in which it was defined. Just as a note — last value in lambda or proc will be returned as a result of .call invocation, so use return when it makes sense, which is not about previous example, a better example of immediate return could be:

class Array

def has?(target)

each { |item| return true if item == target }

false

end

end [1,2,3,4].has?(2) # => true

[1,2,3,4].has?(5) # => false

So, each is a method which iterates through every item of array with invocation of code in the curly brackets for every item in array and in the place where item equal to target we return true right from has? method and only in case if nothing was matched during iteration then false will be returned.

What about ‘block’?

In the above example, you may already notice something similar to proc or lambda , something in curly brackets which was passed to each method without proc or lambda keywords — block . It’s one of the things Matz is proud of, thing which is on every corner in Ruby world, no keywords needed no constructors only block of code in {} or do end and named block , how it could be named in a better way?;) Ok, it’s cool, but we already have proc and lambda why do we need something new? — It’s not new, it’s just simple Proc but constructed in place of method invocation in an elegant way, but since it’s not a regular argument which we are passing into the method, it needs to be handled differently:

def perform_block(&block)

block.call if block

end # or def perform_block

yield if block_given?

end perform_block # => nil

perform_block { "Hello!" } # => "Hello!"

As you can see we need a special sign & for argument which will receive block and then we could simply access our variable which will contain our proc instance, also we could use a special method yield for invocation and block_given to check if the block was passed. The fact that we have block doesn’t mean that we could not create proc manually and pass it to method explicitly, even more, we could convert proc and lambda to block argument:

def perform_proc(my_proc = nil)

my_proc.call if my_proc

end greeting = proc { "Hello!" }

perform_proc(greeting) # => "Hello!" perform_block(&greeting) # => "Hello!"

perform_block(&-> { "Convert lambda to block" })

Conversion of lambda to method's block argument doesn’t mean that we change its behavior, so yield or block.call will invoke the same lambda which we pass to the method as block

More ways to ‘return’

if we still need immediate return of some value from proc without returning from the scope in which it was defined we could use next keyword which for lambda works the same as return :

class Array

def replace(target_value, new_value)

map do |item|

next new_value if item == target_value

item

end

end

end [1, 2, 3].replace(2, 'X') # => [1, "X", 3]