0

Please consider the following different ways to define method m:

  • Method 1:

    class C
      def m; yield; end
    end
    
  • Method 2:

    class C
      def initialize
        (class << self; self; end).class_eval do            
          define_method(:m){|&b| b.call }
        end
      end
    end
    
  • Method 3:

    class C
      def initialize
        (class << self; self; end).class_eval do            
          define_method(:m){puts block_given?; yield}            
        end
      end
    end
    

Then I can invoke m using Object#send.

o = C.new
o.send(:m) {puts 'test'}

While calling m using Method 1 or Method 2 works fine, Method 3 gives this error:

no block given (yield) (LocalJumpError)

I understand that a block is not an object, but instead just a part of method calling syntax and you cannot pass an implicit block from one function to another without writing something obscure like this:

def printer
  yield
end
def proxy
  printer &Proc.new
end

proxy { puts "&Proc.new probably creates Proc object from block"}

But in that case, why does Method 1 work? It would be awesome to get an answer which would explain what's happening under the hood.

5
  • It is not clear what you mean by "define ... statically", "with an explicit block", or "the first case". I can guess you are probably mentioning either your Method 1, Method 2, or Method 3, but it is not clear which. Commented Oct 12, 2014 at 15:43
  • @sawa I thought it would be clear with the code fragment. You quotted Method 1, Method 2 and Method 1 respectively:) Commented Oct 12, 2014 at 15:48
  • Why did you use send to call m? It doesn't look like it has any meaning. Commented Oct 12, 2014 at 15:59
  • @sawa this code is derived from a context where it should be called like that, but in this particular case it doesn't seem to matter. Commented Oct 12, 2014 at 16:14
  • 1
    In case you are not aware, in Method 2 you could call class_eval on the class, rather than on the singleton class: self.class.class_eval do. Commented Oct 12, 2014 at 17:02

1 Answer 1

3

The problem with Method 3 is the scope. yield refers to the block passed to initialize, if any. It does not refer to the block passed to m. And since you created o by C.new without a block, the expected yield is absent, and that causes the error.

In Method 1, yield refers to the block passed to m. In Method 2, b refers to a proc converted from the block passed to m.

Sign up to request clarification or add additional context in comments.

2 Comments

Ah, I see! But is it possible to use yield in a dynamically defined method?
See this.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.