5 ms·
What Is the Difference Between a Block, a Proc, and a Lambda in Ruby? (2013)
- vidarh 1y agoSeparating out blocks this way is pretty meaningless. Blocks are a syntactical construct that can be optimized a certain way, and is in MRI. You can obtain a value of a block by naming it, and when you do, what you obtain is a proc. A Ruby implementation could if it chooses make any block a proc, because you shouldn't be able to tell the difference without extensive contortions (e.g. you could iterate over ObjectSpace and show that a block causes the creation - or not - of an object of the Proc class). And in-fact my (woefully buggy and incomplete) Ruby compiler prototype does just that.
- jez 1y agoI think this is the important point. Something I've mentioned about blocks in Ruby before: if you’re prototyping a new interpreted language and don’t want to have to build a JIT that can optimize code, but still want some semblance of good performance, the block approach Ruby picks can be pretty useful. Ruby doesn’t haven to allocate a full-on, garbage-collected, closure object every time a function accepts a block: it only has to do this if the block gets stored to a variable. If the block is only ever yield’d to, the allocation can be skipped. And when your language’s primary looping mechanism is done with blocks, the difference adds up: xs.each do |ys| # with normal closures and no fancy JIT, # the VM has to allocate a closure once per loop: ys.each do |y| end end Ruby was able to get away with its closure-heavy standard library APIs without a JIT for almost 3 decades because of the affordances that blocks provide over procs/lambdas.
- drnewman 1y agoThat's insightful
- maxlapdev 1y agoFor those unaware, Ruby blocks (and procs) are more flexible than anonymous functions as most language implement them. The article briefly goes over that, mentioning that lambda (regular anonymous functions) and procs (blocks) don't treat execute `return` the same way. There are also particularities with regard to next (continue) and break. I made a post about the niceties of blocks: https://maxlap.dev/blog/2022/02/10/what-makes-ruby-blocks-great.html https://maxlap.dev/blog/2022/02/10/what-makes-ruby-blocks-gr...
- jbverschoor 1y agoWhich is exactly what I don’t like about them. They should’ve used a different keyword or something. This runs you into problems similar to missing a break in such statements with many language
- HellzStormer 1y agoI don't understand what problem you are referring to? A different keyword for what? for the return? for the break? Care to share an example problem?
- jbverschoor 1y agoReturn for example would be return_caller or something (naming is hard) Return in lambda/proc is error-prone
- chowells 1y agoFlexible in a way, sure. But non-locality is generally a bad property, not good. Adding it is a workaround for all the enumeration methods using blocks in a way that makes people think they're weird looping syntax instead of a fundamentally different idea. People want to do early returns from looping over a collection, so take the easy solution of adding more messy language semantics instead of finding a semantically simple solution instead. (For that matter, have fun working out the semantics of break and next when used in a block that isn't an argument to an enumeration method. How do you as a method author opt in to distinguishing between the two after yielding to a block?) This is generally the case with Ruby everywhere. Why does that thing have an edge case with weird semantics? To work around the edge case with weird semantics somewhere else. It's all fine if you want to just try things until something works. But if you want to really understand what's going on and write code that's a first-class participant in the language features, it gets really frustrating to try to deal with it all.
- paulddraper 1y agotl;dr A block is a part of the AST. Like a pair of braces. A proc is a function. A lambda is a proc that treats args and returns differently.
- endorphine 1y ago> Lamdas check the number of arguments, while procs do not FWIW, Matz himself called this difference "a design mistake".
- weaksauce 1y agowhich way would he have liked to be the "correct way"
- drnewman 1y agoI'd think the preferred way would be to implement them as a separate class. That'd be more in line with the design of other core classes (like TrueClass & FalseClass). It'd also have created the opportunity to create a "Callable" protocol early in the design which would have been great, and would harmonize with the design of Ruby's many other protocols Enumerable, Comparable, Range-compatible values, etc.
- jez 1y agoDo you have a source for this?
- endorphine 1y agoHe mentioned it in-person to me.
- drnewman 1y agoYeah, I think I've heard that too.
- kubb 1y agoWhat happens when you return from a proc when the enclosing function has already returned?
- lcnPylGDnU4H9OF 1y agoYou can't call return from inside a Proc inside a method; you will encounter a LocalJumpError.
- vidarh 1y agoYou can call return from inside a proc all you want. You can't do so if you return the proc to an outside scope without getting LocalJumpError. E.g, given: def foo = proc do 42 end def bar = proc do return 42 end Then `foo.call` is fine, but `bar.call` will indeed give a LocalJumpError as you say. But a return in a proc that hasn't escaped its defining scope is fine: def baz = proc do return 42 end.call Calling `baz` here will just return 42 to the surrounding scope.
- vidarh 1y agoThis example: def foo proc do return 42 end.call end def bar proc do return 42 end end p foo p bar.call Will produce: 42 test.rb:11:in `block in bar': unexpected return (LocalJumpError) from test.rb:16:in `<main>' So in other words, it's handled.
- whalesalad 1y agoThis is the biggest wart on the Ruby language by far.
- digianarchist 1y agoThe fact that there was a book written on this tells me that it's more complicated than it needs to be: https://www.goodreads.com/book/show/35980970-mastering-ruby-closures https://www.goodreads.com/book/show/35980970-mastering-ruby-... (not sure why the book was removed from the Pragmatic Bookshelf website).
- dragonwriter 1y agoI suspect that it is connected to what appears to be the in-progress new edition the author is doing outside of pragprog, though what the exact connection is I couldn't guess. https://leanpub.com/therubyclosuresbook https://leanpub.com/therubyclosuresbook
- digianarchist 1y agoThat was published before. I think they “upgraded” to publishing via Pragmatic Bookshelf
- dragonwriter 1y agoOh, weird then. The errata and samples are still up at Pragprog, but not the book page, which suggests something quite unusual.