How to validate the block signature?

The following example is working even if the block signature in the second call is different from the definition. Is this expected behaviour or a bug?

def hello(&block : String, String -> String)
  puts "---"
  puts typeof(block)
  puts "Before Block"
  puts block.call("1", "2")
  puts "After Block"
end

hello do |first, second|
  "#{first} #{second}"
end

hello do |first|
  "#{first} only"
end

Output:

---
Proc(String, String, String)
Before Block
1 2
After Block
---
Proc(String, String, String)
Before Block
1 only
After Block
$ crystal --version
Crystal 1.3.2 [932f193ae] (2022-01-18)

LLVM: 10.0.0
Default target: x86_64-unknown-linux-gnu

This is expected behavior. The caller can omit block arguments but not add extra ones. The reason is that we want to allow things like this:

3.times do
  puts "Hello!"
end


10.times do |i|
  puts "#{i}**2 = #{i**2}"
end 

That is, an argument is always given to the block, but the caller might choose to omit it.

A follow up question is: what API are you trying to achieve?

1 Like

That makes sense. Thanks.

A follow up question is: what API are you trying to achieve?

API is not broken, it was just confusion. Now it is clear.

This is used in the Storage Manager project for Kadalu Storage/GlusterFS. Today I accidentally discovered that all tests passed even without all the block arguments (GH issue).

Example helper to create CLI subcommand: mgr/src/cmds/helpers.cr
and its usage: mgr/src/cmds/volumes.cr

1 Like

Incredible and very well done project (Kadalu).

1 Like