I have the following class :
class X
property son, val
def initialize(@val : Int32)
@son = nil.as X?
end
def add(other : X?)
unless other.nil?
if @son.nil?
@son = other
else
@son.add(other)
end
end
end
end
x = X.new 5
x.add(nil)
x.add(X.new 3)
But when I try to build
I get
Showing last frame. Use --error-trace for full trace.
In nil-test.cr:12:22
12 | @son.add(other)
^------
Error: undefined method 'include' for Nil (compile-time type is (X | Nil))
According to the manual, this is exactly the kind of situation where the compiler should recognize that @son
cannot be nil
in the else
branch, yet it apparently fails to do so.
What am I doing wrong ?
Note : using @son.not_nil!.add(other)
works, I'm just asking why the compiler can't do without.
That only works for local variables, not instance variables - since the instance variables may be mutated by another fiber between the condition and you accessing the variable. See this section (under "Limitations") in the Crystal docs.
You can do it like this, assigning the instance variable to a local variable that will not change out from under you:
def add(other : X?)
unless other.nil?
if s = @son
s.add(other)
else
@son = other
end
end
end