| Blocks in Smalltalk (to my understanding) are closures. Blocks in Ruby are closures that also bring the call stack they were created in with them. One way to think of about it is this: anonymous functions as originally implemented in early Lisps are code as an object, closures are code with its lexical environment as an object. You can think of a Ruby block as code with its lexical environment and its call stack as an object. So they don't just handle return differently than closures, they have access to the call stack of the site where they're created like a continuation. This is why they handle return differently, but this is just one of the things that falls out from that. It also comes with other control flow features like "redo", "retry", "next", "rescue", "finally", and others. These are all call stack control (control flow) conveniences, just like return is. All of them can be thought of as being abstractions built on top of continuations (just ask a Scheme hacker). Originally Ruby was basically a Lisp without macros, but with continuations, a Smalltalk like object system and a lot of syntactic affordances inspired by Perl, and other languages. Blocks are one of the conveniences built on top of the Lispy semantics. Note that I'm explaining how blocks work as an abstraction (vidarh below explains how they work as a concretion, as implemented in MRI). |
At-a-glance afaict Smalltalk provides those features too, so I would guess Smalltalk blocks may have access to the call stack too?
https://drcuis.github.io/TheCuisBook/The-Debugger.html