Initialization with `yield` doesn't work

Could you please explain me why this code doesn’t work and if it is by design?

module Foo
  def initialize(foo : String, &block : String ->)
    yield foo
  end
end

class Bar
  include Foo

  @bar : String

  def initialize(foo : String)
    super do |foo|
      @bar = foo
    end
  end
end

Bar.new("baz")
Error in test_initialize_yield.cr:19: instantiating 'Bar.class#new(String)'

Bar.new("baz")
    ^~~

instance variable '@bar' of Bar must be String, not Nil

Error: instance variable '@bar' was used before it was initialized in one of the 'initialize' methods, rendering it nilable

Quote from Crystal Docs (https://crystal-lang.org/reference/syntax_and_semantics/blocks_and_procs.html):

When using blocks with yield , the blocks are always inlined: no closures, calls or function pointers are involved. This means that this:

def twice
  yield 1
  yield 2
end

twice do |i|
  puts "Got: #{i}"
end

is exactly the same as writing this:

i = 1
puts "Got: #{i}"
i = 2
puts "Got: #{i}"

Workaround is doing @bar : String | Nil, but it’s still not clear why it doesn’t work if blocks are inlined :thinking:

It’s exactly the same performance-wise, not in semantics. The docs are a little misleading, but the section you quoted is clearly under the “performance” heading.

I see, thanks for the response. Looks like the compiler isn’t sure for 100% if there will be a yield in the super.