Provided sample shows the problem:
class Foo
def initialize
@bar ||= true
end
end
Foo.new
Above fails with:
Error in line 7: instantiating 'Foo:Class#new()'
instance variable '@bar' of Foo must be Bool, not Nil
Error: instance variable '@bar' was used before it was initialized in one of the 'initialize' methods, rendering it nilable
Isn't this the expected behaviour? It expands to @bar = @bar || true, and since @bar is not initialized it doesn't work.
Technically it's correct, although Ruby for instance treats it just as nil and invokes the _else_ branch which is more intuitive to me as well.
Crystal evaluate the type of instance variable from initializer (both initialize method and catch-all initialization )
So when Crystal saw your code above, it considered @bar as Bool from @bar ||= true.
(that will be treat as@bar = @bar || true and the only known type in the right side is true : Bool)
You can do this now for nilable instance variable:
class Foo
@bar : Bool?
def initialize
@bar ||= true
end
end
Foo.new
Whenever I see such code in Ruby I think "But... why?". An initializer initializes an object. There's no previous state for the object. So it doesn't make sense to do ||= there. So basically this is equivalent, and simpler:
class Foo
def initialize
@bar = true
end
end
Foo.new
So here the compiler is forcing you to have simpler code. I think that's something good.
@Sija Unless there's a really strong reason you need this, I'd say to close this issue.
I'll close this. Please reopen if you need to.
I agree, thanks for review!
Most helpful comment
Whenever I see such code in Ruby I think "But... why?". An initializer initializes an object. There's no previous state for the object. So it doesn't make sense to do
||=there. So basically this is equivalent, and simpler:So here the compiler is forcing you to have simpler code. I think that's something good.
@Sija Unless there's a really strong reason you need this, I'd say to close this issue.