The first assignment binds x to Array{Matrix} and the second to Matrix. The type of the object x is bind to changes in the code. Code is for illustration only and of course I can do x=sum(rand(3,3) for i in 1:10) but often due to readability I want to break the logic.
I donβt think itβs good practice because for a reader who finds x later in the code, they might skim the code for the origin of that variable and find only line 1, but not line 2. As that could be confusing I try to avoid variable rebinding. Also, if one name can describe two different things, itβs probably not a good name.
I was not expecting this, but actually this does can introduce problems (is this a bug?):
julia> function f()
x = 1
x = [ x for i in 1:2 ]
return x
end
f (generic function with 1 method)
julia> @code_warntype f()
Variables
#self#::Core.Const(f)
#5::var"#5#6"
x@_3::Core.Box
x@_4::Union{}
Body::Any
1 β (x@_3 = Core.Box())
β Core.setfield!(x@_3, :contents, 1)
β (#5 = %new(Main.:(var"#5#6"), x@_3))
β %4 = #5::var"#5#6"
β %5 = (1:2)::Core.Const(1:2)
β %6 = Base.Generator(%4, %5)::Core.PartialStruct(Base.Generator{UnitRange{Int64}, var"#5#6"}, Any[var"#5#6", Core.Const(1:2)])
β %7 = Base.collect(%6)::Vector{_A} where _A
β Core.setfield!(x@_3, :contents, %7)
β %9 = Core.isdefined(x@_3, :contents)::Bool
βββ goto #3 if not %9
2 β goto #4
3 β Core.NewvarNode(:(x@_4))
βββ x@_4
4 β %14 = Core.getfield(x@_3, :contents)::Any
βββ return %14
while:
julia> function f()
x = 1
y = [ x for i in 1:2 ]
return y
end
f (generic function with 1 method)
julia> @code_warntype f()
Variables
#self#::Core.Const(f)
#7::var"#7#8"{Int64}
y::Vector{Int64}
x::Int64
Body::Vector{Int64}
1 β (x = 1)
β %2 = Main.:(var"#7#8")::Core.Const(var"#7#8")
β %3 = Core.typeof(x::Core.Const(1))::Core.Const(Int64)
β %4 = Core.apply_type(%2, %3)::Core.Const(var"#7#8"{Int64})
β (#7 = %new(%4, x::Core.Const(1)))
β %6 = #7::Core.Const(var"#7#8"{Int64}(1))::Core.Const(var"#7#8"{Int64}(1))
β %7 = (1:2)::Core.Const(1:2)
β %8 = Base.Generator(%6, %7)::Core.Const(Base.Generator{UnitRange{Int64}, var"#7#8"{Int64}}(var"#7#8"{Int64}(1), 1:2))
β (y = Base.collect(%8))
βββ return y
I am not sure if I agree or understand this in this way. My impression is that, in the code above, the types should be perfectly inferreable in both cases, and the variable label should be irrelevant.
Yes, I expect that is true in this example, but I would err on the side of avoiding changing the type of a variable so you donβt need to analyze those lower level details to see whether everything is inferred stably.
Indeed, initially I thought that it was only not recommendable for code readability, but it can make more harm than that (maybe this instability is something related to the garbage collection?).