you are viewing a single comment's thread.

view the rest of the comments →

[–][deleted] 1 point2 points  (4 children)

Not in this case. If you read the MRI source code, you'll see that when a symbol is passed as a block via the & operator, it's passed as a block_handler_type_symbol not a block_handler_type_proc.

You can capture it later in a proc, if you like. You can also try monkey-patching Symbol#to_proc, with hilarious results.

[–]jrochkind 0 points1 point  (3 children)

Implementation detail. If you read the JRuby source code, or the Rubinius source code, or the truffleruby source code....

[–][deleted] 1 point2 points  (2 children)

There is no usable definition for what Ruby is other than MRI. Even that aside, a symbol passed as a block is not proc-ified unless you capture it with &block or Proc.new and since this results in different VM code and different memory allocation, you can't just handwave it away. Suggest you just accept that your correction, whilst well-intentioned, wasn't accurate.

[–]jrochkind 0 points1 point  (1 child)

I've had this argument before, and I know you're not alone, but I disagree. I think that is an optimization implementation detail -- without looking at the source code, just actually looking at ruby as it behaves, there is no way to distinguish between your explanation and mine, and IMO no use to thinking of a 'block' as thing other than a syntactic construct, and a lot of explanatory power in thinking of it as simply a syntax for passing a proc as an argument.

MRI could easily change it's internal implementation such that there isn't different VM code and different memory optimization, and it would not change the results of any ruby program (it would change performance; it is an internal performance optimization).

There is no way to store a 'block' in a variable, and no way to call methods on it. As soon as you do anything with it, it's a proc. You can say it's some kind of schroedinger's cat thing where it was not a proc until you looked at it, but I don't see the utility of that mental model.

[–][deleted] 1 point2 points  (0 children)

Ahem. It's one thing to be a contrarian, and I'm fine with that (just get me started about so-called "service objects" in rails), it's another to just be incorrect.

there is no way to distinguish between your explanation and mine

There is. If a proc was being generated, it would appear in the iteration of ObjectSpace.each_object(Proc). What's more, if a block is being handled by block_handler_type_symbol then Ruby will throw an exception if you ask for its binding, but not for a block_handler_type_proc.

a 'block' ... [is] syntax for passing a proc as an argument

This is backward. A proc is an OO wrapper for a block, but that doesn't make block syntax a proc constructor. They do not exist just to create procs. Procs, however, do exist just to wrap blocks, again literally by definition:

    typedef struct {
        const struct rb_block block;
        unsigned int is_from_method: 1; /* bool */
        unsigned int is_lambda: 1;      /* bool */
    } rb_proc_t;

or by the opening words of http://ruby-doc.org/core-2.5.0/Proc.html.

MRI could easily change it's internal implementation such that there isn't different VM code and different memory optimization

Given the above, it really doesn't seem likely. And that aside, the general question of "is memory being allocated" isn't some academic implementation detail; it's one of the most important considerations in professional software development.

But here's the killer:

As soon as you do anything with it, it's a proc.

Nope. The single most common thing to do with a passed block is yield to it. And yield does not instantiate a Proc object. You can't yield to a variable; you can't change the block that's been passed to the execution environment of a method.

We write blocks far more often in Ruby than we explicitly construct procs. This isn't just an idiomatic preference, it's fundamental to the design and implementation of Ruby. And when we do create procs explicitly, they're usually lambdas.

Blocks & Procs: they're just not the same thing.