Search code examples
crystal-lang

type narrowing not work if type is specified?


class Foo
  def initialize(@foo : String | Nil)
  end
  def foo
    @foo
  end
end

a = Foo.new "213"
if !a.foo.nil?
  puts a.foo, typeof(a.foo)
end

get output of

213
(String | Nil)

but shouldn't type of a.foo be narrowed to String? Is this another design limit?


Solution

  • The compiler doesn't know that @foo doesn't change. Say your class Foo has a setter for @foo. If some concurrently running code uses that setter to set @foo to nil, the second call to Foo#foo inside the if condition might return nil now even though the check passed before.

    You can remedy by introducing a local variable which the compiler can reason about:

    if foo = a.foo
      puts foo, typeof(foo)
    end