class A
getter :a, :b
def initialize(@a : Symbol, @b : Symbol = @a)
end
end
a = A.new a: :xx
puts a.b
#output :skip
Thank you for reporting this!
That :skip
looks mysterious, but it's just the symbol with number 0. This proves it:
class A
getter :a, :b
def initialize(@a : Int32, @b : Int32 = @a)
end
end
a = A.new a: 1
puts a.b # => 0
Definitely a bug, though.
And I think the most probable solution we'll do is to disallow this (using instance variables in default values), it's pretty hard to implement.
Note that using just the param works
. I agree to disable ivars as default. Maybe a hint in case the ivar is assigned with this pattern could be added.
class A
getter :a, :b
def initialize(@a : Int32, @b : Int32 = a)
end
end
a = A.new a: 1
puts a.b # => 1
And I think the most probable solution we'll do is to disallow this (using instance variables in default values), it's pretty hard to implement.
@asterite why is it hard to implement ?
Can't we just detect an ivar access, and verify that it has been set before ?
class Foo
@a : Int32
@b : Int32
@c : Int32
# This is invalid, @c is used before initialization
def initialize(@a, @b = @c, @c = 42)
end
# This is valid, @a has been initialized before
def initialize(@a, @b = @a, @c = 42)
end
end
When/If #6007 is merged, we'd need to be careful and properly use the __arg0
instead of @a
when initializing @b
, but that's doable I think.
Checked in Crystal 0.31.1 on MAcOS.
$ crystal --version
Crystal 0.31.1 (2019-10-02)
LLVM: 8.0.1
Default target: x86_64-apple-macosx
Ary's example now gives a different result:
class A
getter :a, :b
def initialize(@a : Int32, @b : Int32 = @a)
end
end
a = A.new a: 1
puts a.b # => 0 (NO LONGER OUTPUTS 0)
Gives an error now
$ crystal test.cr
Showing last frame. Use --error-trace for full trace.
Error: instance variable '@a' of A must be Int32, not Nil
Instance variable '@a' was used before it was initialized in one of the 'initialize' methods, rendering it nilable
The original example shows the same error as shown above.
And Brian's example works as it did before and outputs 0
.
Indeed, it seems to be fixed now, or at least it doesn't lead to incorrect code anymore.
Most helpful comment
And I think the most probable solution we'll do is to disallow this (using instance variables in default values), it's pretty hard to implement.