In Crystal you need to declare the type of the block parameter if you want to capture and forward it. If you omit any type restriction, the implicit type is Proc(Nil). Thus it does not accept any block parameters.
I come from Ruby too, i consider specify type for block parameter is really useful, and clearly, it make code readable, this is statically typed language, you have to accept the trade off, not bad, this is good part.
Following is the working code.
def thrice(&block : Int32 ->)
foo(&block)
end
def foo(&)
puts "Before 1"
yield 1
puts "Before 2"
yield 2
puts "Before 3"
yield 3
puts "After 3"
end
thrice do |i|
if i == 2
next
end
end
puts "end"