Fun fact: Both yield and block.call may never return. The block is free to return from its enclosing method, which effectively pops multiple frames, including foo and possibly more, off the stack.
As an aside, this is one of the key differences between a lambda and a proc. Last I checked, you can pass a lambda as a block, but it is implicitly converted to a proc.
It’s more the opposite, arrow functions treat `this` as a regular lexical variable, it’s normal functions which special-case `this`.
The distinction between a block and a Proc is an implementation detail - an implementation can choose to always make blocks Procs (my experimental Ruby compiler does just that) and a program shouldn't be able to tell the difference.
The distinction between proc and lambda with respect to how returns are handled provides significant utility with very low added implementation complexity that for the most part work together to do what people will expect of them.
That is, the most logical reading of the block syntax is that a return will return from the function it is lexically in, so it does, while a lambda looks like a function, and acts accordingly.
If anything, to me these are prime examples of what makes Ruby a great language that values developer happiness over pointless exercises in purity.
And arguments may be passed either positionally or by name.
Blocks are the weird part, they have special support because they're a bunch of syntactic sugar / magic, which doesn't even have to be part of the function's prototype e.g
"yield" will invoke the implicit block, "block_given?" is a metamagic kernel method which checks if the current context was passed a block.I haven't kept up to date with Ruby so I don't know if that style is still en vogue. The equivalent "explicit" version is
in which the block — if passed — is reified to a Proc, which you can manipulate normally. If no block is used, then `block` will just be `nil` (as the essay notes, blocks are always optional).