Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

Is a block basically a lambda or is there more to it?


Assuming that by lambda you mean "an anonymous function"[1], for most intents and purposes they are, except their returns are non-local whereas functions usually have local returns.

However blocks are special forms of the language, unless reified to procs they can only be passed as parameter (not returned), and a method can only take one block. They also have some oddities in how they interact with parameters (unless reified to lambda procs).

[1] because Ruby has something called "lambda procs"


Basically. But Ruby has two types of lambdas, one called lambda, and one called proc. Blocks act like the second type.

The difference is that if return is called in the former, you return to the expression after where it is called, while I'm the latter return returns from the scope where it is defined.

This is usually going to feel reasonably intuitive, but can become weird if you e.g. reify a block into a named object and pass it around.

It can be very useful though. E.g. you can pass a block down into a recursive algorithm as a means to do a conditional early exit when a given criteria is met.

Notably you can do this even if a piece of code takes a named argument instead of a block and doesn't anticipate that use and expect you to pass a lambda instead of a process...

In most of the typical uses of a block, most people will just naturally expect the behaviour you see, because the block looks and feels like part of the scope it will return from.


My understanding is that the 'extra thing' is control flow - blocks can force a return in their calling scope. For example a loop that calls a block may be terminated/skipped by a break/continue statement in the block itself. However I'm not a Ruby programmer, so please check my working.


Blocks can force a return in their defining scope. If you pass a block down through multiple methods and then call it, the return will exit the lexical scope the block was defined in, not the method it was ultimately called from.

It usually looks pretty much the same, and so for most intents what you described is "close enough" to get most used of blocks.


They are closures. But Ruby can do interesting and slightly reckless things, like transplanting a closure into a different evaluation scope. It’s very powerful, and also very dangerous in the wrong hands.


Sounds a bit like a lisp macro? Or in JS using eval?


It's a closure. The lisp equivalent is also a closure, and the JS equivalent is a function (which is a closure as they can refer to variables in the scope they're defined in. To test this define a function inside a function and reference variables defined in the outer function, and return the inner function).


I mean, that is the point of a closure. The name refers to closing over its environment.

In terms of implementation, the closure needs to keep a reference to its environment, so it may be "transplanted" but it effectively runs in its own scope.


That's what I'm saying: In Ruby, you can transplant code from a closure out of its lexical scope and evaluate it as if it was defined in a different environment.

Should you ever do this? No. But you can. :-)


My point is that this isn't "reckless" - it's a core part of the value of a closure.

We do this regularly enough in Ruby - usually with lambda rather than proc/blocks because of the return semantics, but you can do it just as safely with proc/blocks as long as you don't call "return" within them (there's no reason to, on the other hand).

It's a way of e.g. building generator methods that returns distinct callable objects without constructing a whole class. In that case the closure environment effectively becomes the instance variables.


It is the opposite of what a closure typically means, because it is precisely not “closing” over its lexical scope.

It’s an interesting feature to be sure, and it enables some really beautiful things, but it also enables some incredibly difficult bugs.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: