Proposed not allowed specify block return type like `Type ->` instead of `Type -> Nil`, in the Crystal 2.0

AFAIK, following code.

   def foo(&block : Int32 ->)
     block
   end

exact same as following code, right?

   def foo(&block : Int32 -> Nil)
     block
   end

Former always confusing me, because I can’t remember, is it same as Int32 -> _ or Int32 -> Nil ?

When we said Ruby, there are many alias method, it more readable on some cases, but it make newbie confuse too, Crystal not do like this as said the the official to Rubyist doc, so, I propose we don’t need two different ways of writing same things.

BTW: From an aesthetic perspective, the latter is also more symmetrical.

To me, the Int32 -> format is a nice shorthand for “receives an Int32 and the return value is useless”. That implies that the block is used entirely for side effects based on the block inputs and maybe receiver state.

It’s implemented as implicitly returning Nil and that makes sense.

It’s implemented as returning whatever the return value of the block(s) are.

def foo(&block : Int32 ->)
  yield 1
end

foo { |_| "string" } # => "string"
2 Likes

Fascinating. If you use block.call it returns nil.

def foo(&block : Int32 ->)
  block.call 1
end

def bar(& : Int32 ->)
  yield 1
end

pp! foo(&.to_s)   # => nil
pp! foo(&.itself) # => nil
pp! bar(&.to_s)   # => "1"
pp! bar(&.itself) # => 1

This is somewhat expected: Capturing blocks - Crystal

Note that if the return type is not specified, nothing gets returned from the proc call:

So it infers it to be nil when captured if you don’t specify it.

yield usage is inlined.

IIRC, returning whatever the return value of the block(s) are is:

def foo(&block : Int32 -> _)
end