4 ms·
> blocks -- syntactic support in the language for cleanly passing a single in-line defined lambda/closure object as an argument -- are possibly the thing that a
by chowells 5y ago
> blocks -- syntactic support in the language for cleanly passing a single in-line defined lambda/closure object as an argument -- are possibly the thing that are most special to ruby.
Too bad ruby stopped short of doing the trivial obvious thing and just making blocks be regular values. Instead the language is complicated by special syntax and functions for sending and receiving blocks, and bizarrely limited by the inability to do anything with a block literal other than send it.
Blocks were so close to being good. They managed the triple flip with a double twist, but they couldn't stick the landing. It's not quite a faceplant at the end, but it clearly shows how much better they could have been.
- gwright 5y ago> Too bad ruby stopped short of doing the trivial obvious thing and just making blocks be regular values. Instead the language is complicated by special syntax and functions for sending and receiving blocks, and bizarrely limited by the inability to do anything with a block literal other than send it. Blocks are syntactical structures. Your statement is like saying that the parens and commas that are part of the argument list should be "regular values". I'm not sure what you want to do with a "block literal". If you want to do something with the closure represented by the block, then reify the block into an object to pass it around, wrap it, introspect etc. I think a lot of confusion about blocks in Ruby is really inconsistent terminology. Using "block" to mean the syntactic expression of a closure, i.e. part of the method call syntax I think helps to disambiguate the syntactical nature of closures from the closure reified into an object that you can pass around, call, etc. (i.e. an instance of the Proc class)
- chowells 5y ago> Blocks are syntactical structures. Your statement is like saying that the parens and commas that are part of the argument list should be "regular values". Well, no. Know what else is a syntactic structure? Numeric and string literals. People would never have touched the language in the first place if Ruby required you to write code like x = String("abc") y = Integer(123) But people bend over backwards to explain why z = { |x| x + 1 } Is bad and shouldn't be allowed. What? The whole block vs proc thing is an artificial distinction. It doesn't add value, it removes it. (Yeah, I know about the difference in how they handle return. This strikes me as an incredibly ad-hoc way to address something they could have solved a lot more elegantly.)
- dragonwriter 5y ago> But people bend over backwards to explain why “z = { |x| x + 1 }” is bad and shouldn't be allowed. Really? I’ve never seen anyone bend over backward to explain it as bad, mostly just that that's the way it is, there are tradeoffs either way, and its not worth changing. > The whole block vs proc thing is an artificial distinction Presumably, you mean lambda vs. proc. (Both of which are defined using blocks, and procs are what using & syntax in a function signature causes a passed block to be reified into.) But, yes, all distinctions are creations of humans, especially all distinctions within human creations like, say, programming languages. So “artificial distinction” is a meaningless descriptor when we are talking about things in a programming language.
- jdc 5y agoWould it be fair to say you don't want to write this? z = ->(x) { x + 1 } z.call(y)
- fallingknife 5y agoI don't see why there is this distinction where lambdas have to be called differently than functions.
- vidarh 5y agoRuby doesn't have functions. It only has methods. That blocks in MRI happen to be implemented without reifying an object is an optimisation. You can only ever obtain a reference to said block by reifying it into a Proc instance. Letting you obtain some kind of raw reference to a block that isn't a method on an object would make blocks unlike every other value in Ruby.
- dragonwriter 5y ago> I don't see why there is this distinction where lambdas have to be called differently than functions. Ruby doesn't have functions; things that look like bare (non-method) function calls in other languages are just method calls on self. So procs/lambdas can't be called the same as, or differently from, functions—they are the closest thing Ruby has to functions to start with.
- dragonwriter 5y ago> Too bad ruby stopped short of doing the trivial obvious thing and just making blocks be regular values. Abstractly, I kind of see the point, in practice, I don't see it makes much difference, and given Ruby’s two flavors of function-like objects, it seems to work out for the best. > the inability to do anything with a block literal other than send it. But sending lets you do anything else you’d want to to do with it. Specifically, to get either of the flavors of callables, you pass it to “proc” or “lambda”, and then use the result.
- masa331 5y agoYou have that with procs and lambdas
- hnav 5y agoWhat do you mean by inability to do anything with a literal? You can capture it, turn into a variable, turn it into a "lambda" (make next, break, return local), use it like callbacks are used in any other language. Blocks are a bit special in that they go in their own slot for message sends (method calls) which allows the syntax to be unambiguous and the yield keyword allows for optimized calls to passed in blocks because methods that don't reference a block as data don't have to worry about the block outliving the stack frame.
- chrisseaton 5y agoNo there’s special methods which turns blocks into objects, and there’s a syntax to do that, but blocks aren’t objects unless you specifically do one of those things. The idea you’re replying to is that they’d be objects always.
- hnov 5y agodef proc &p p end is what the special method looks like but yeah they’re not standalone expressions but rather part of the method call syntax.
- hvis 5y agoNot having every block be a separate value makes it easier for the Ruby VM to optimize such code without escape analysis (which is something that's pretty hard to do in this language). Don't have to allocate the container => don't need to use the heap one more time. Nor access the block's code through that indirection. Same thing with methods: they aren't objects, but you can create an object pointing to a method any time you need one.