From a language design perspective, why aren't ruby blocks first-class?
Similarly, I think blocks should actually be lambdas, thereby getting rid of the need for cumbersome syntax such as proc {...}.call or &proc or lambda or Proc.new. This would get rid of the need for yield too.
Ruby doesn't have first-class functions, but it does have closures in the form of blocks, procs and lambdas. Blocks are used for passing blocks of code to methods, and procs and lambda's allow storing blocks of code in variables.
Blocks are a handy and powerful feature in Ruby, and we can use them anywhere. Blocks are anonymous pieces of code that accept input from arguments and return a value.
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.
A ruby block is one or more lines of code that you put inside the do and end keywords (or { and } for inline blocks). It allows you to group code into a standalone unit that you can use as a method argument.
From a language design perspective, why aren't ruby blocks first-class?
Mostly for performance reasons, in as far as I'm aware. Consider:
def test_yield
yield
end
def test_block &block
block.call
end
la = lambda {}
def test_lambda l
l.call
end
Then, benchmark with an empty block for the first two, vs the third with a new la
per call or with the same la
, and note how much faster the yield goes in each case. The reason is, the explicit &block variable creates a Proc object, as does lambda, while merely yielding doesn't.
A side-effect (which I've actually found uses for, to recursively pipe passed blocks through the use of a proc object), is you cannot yield in a proc or lambda outside some kind of enclosing scope:
foo = proc { yield if block_given? }
foo.call { puts 'not shown' }
def bar
baz = proc { yield if block_given? }
baz.call
end
bar { puts 'should show' }
This is because, as I've come to understand it (I lost a lot of hair due to this, until it ticked), block_given? is sent to main when foo calls it, and to bar rather that baz when it gets evaluated in bar.
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