Is this correct?

def thrice(&block)
  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
    break
  end
end
puts "end"

15 | thrice do |i|
^-----
Error: wrong number of block parameters (given 1, expected 0)

while in ruby it can run.

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.

This is also called out in the reference book: Capturing blocks - Crystal.

In Crystal you need to declare the type of the block parameter
has to specify it is a mental burden,
why not like fun def sum(a,b) … and can omit it?

Is it possible to omit it in the future version?

You only need to specify if you want to capture the block. Otherwise in most cases it’s not required.

you can do

def thrice(&)
  foo { |*args| yield(*args) }
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
    break
  end
end
puts "end"

if you don’t need to capture block

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"
1 Like