Method call depending on block type

Overloading based on block type restriction does not work, you’re essentially overriding the previous definition.
I’m combining the excellent answers from @ysbaddaden and @RX14 in Allow method overloading via block type · Issue #5090 · crystal-lang/crystal · GitHub to explain why:

Block arguments are defined by the method that yields, not by how the method is called; the yielding method can’t behave differently depending on the block. You need to find the method before you look at the block, which means block arguments cannot be used to find the method.
It would be technically possible to determine the method based on the number of block arguments, but that’d require removing the ability to skip block arguments (currently yield 1, 2, 3 with a block { |x, y| puts "#{x}, #{y}" } works and prints 1, 2). It’d also be quite confusing, since overloading currently works with both args length and args type, whereas this overloading would only work with length.

So you can use either different names, different regular parameters to create different signatures for both methods.

Another option for this example would be to use regular parameters with different Proc types instead of capturing block parameters. It’s a bit more verbose but semantically completely equivalent:

def add_col2(extractor : String -> _)
  extractor.call("test1")
end
def add_col2(extractor : (String, Int32) -> _)
  extractor.call("test2", 3)
end
add_col2 Proc(String, Int32, Nil).new{|x, y| puts "y=#{y}, x=#{x}" }
add_col2 Proc(String, Nil).new{|x| puts "x=#{x}"}
2 Likes