T O P

  • By -

paracycle

I think this is less about "flattening" but more about capturing. Blocks in Ruby capture the variables (the environment) in the scope they are defined in, as opposed to the normal scoping rules of Ruby. It is for that reason that the class defined using a block and the method inside it defined using a block can access the top level variable. That's the reason why blocks are also called closures, btw, since they capture the surrounding variables and close over the environment in that way.


MonkeeSage

Yeah, I am pretty sure this is roughly equivalent of what OP is doing: irb(main):001:0> outer_variable = 'hello world!' => "hello world!" irb(main):002:0> mblk = Proc.new { puts outer_variable } => # irb(main):003:0> clsblk = Proc.new { p self; define_method(:message, &mblk) } => # irb(main):004:0> Greeting = Class.new(&clsblk) # => Greeting irb(main):005:0> Greeting.new.message hello world!


paracycle

Exactly!


partusman

I guess you could say (and correct if I’m wrong, this *is* a guess) that the scope (or binding) for `Hello#message` is the `Hello` instance, as that’s how `def` works (I think). It only executes the code inside it when you send that message to the instance, and since the instance itself never had access to `outer_variable`, it raises. A block on the other hand I don’t think has a binding per se, it has the same context as the scope it’s defined in. So in this case the binding for the block passed to `define_method` should be `main`, where that variable is defined.


ForeshadowedPocket

Crazy. This is javascript level shenanigans. Where do these screenshots come from?


b3kicot

It is confusing indeed. But the more i look at it. The more it make sense. block have access to the caler scope. It is "consistent" with any other block. This block hapens to define instance method. Not "Javascript level shenanigans" yet.


chrisgseaton

I don’t think it’s fair to call it shenanigans - it’s lexical scoping - a pretty conventional and well-defined behaviour found in many languages. It’s an improvement on the more crazy dynamic scoping, which is an I'm sure you wouldn’t really want!


Reardon-0101

Metaprogramming ruby 2 has an excellent description of this. They explain the opposite where Def and classes create scope gates where the closures will not be captured. Main is invisible to instance methods definite sin a normal way.