crystal-lang / crystal

The Crystal Programming Language
https://crystal-lang.org
Apache License 2.0
19.45k stars 1.62k forks source link

bug proxing block through method_missing #3047

Open kostya opened 8 years ago

kostya commented 8 years ago
class B
  def bl(name, &callback : String -> Int32)
    callback.call(name) + 1
  end
end

class A
  def initialize(@b : B)
  end

  macro method_missing(call)
    @b.{{call}}
  end
end

b = B.new
a = A.new(b)

p b.bl("name") do |x|
  x.size
end

# ====== this is not compiled =======
# p a.bl("name") do |x|
#   x.size
# end
p a.bl("name") do |x|
    ^~

in macro 'method_missing' 

  1.     @b.bl(_arg0) do |_block_arg0|
  2.   yield _block_arg0
  3. end
  4.   

  yield _block_arg0
  ^

can't use `yield` inside a proc literal or captured block

Make sure to read the whole docs section about blocks and procs,
including "Capturing blocks" and "Block forwarding":

http://crystal-lang.org/docs/syntax_and_semantics/blocks_and_procs.html
asterite commented 8 years ago

Yes, this is a known limitation.

I think I'd like the language to support built-in forwarding to another member, similar to how in Go you can "include" another type inside a type and the compiler would check methods in this another type if it can't find them in the current type. This will solve probably 99% of the use cases of method_missing.

kostya commented 8 years ago

sometimes need not only forwarding, but also little processing, rescuing

asterite commented 8 years ago

Then I think this will be solved once we allow yield to be used when a block is captured. But if that happens, it will happen much, much later as it's pretty complex to implement right now.

kostya commented 5 years ago

Meet this problem again. Now i think, why not possible just pass block as it is (as text) in method_missing (add method source for example)? Usage of method_missing is proxying methods.

class A
  macro method_missing(call)
    @b.prefix_{{call.name}} { {{call.block.source}} }
  end
end

and it would add original block here, instead adding this:

do |_block_arg0|
  yield _block_arg0
end
kostya commented 5 years ago

oh, nvm, it would change binding.