A slight confusion with a `let` block

Yep, an equivalent result to falses(L) can be done by removing the macro call:

julia> let L = 5, Q = [false for i in 1:L]
       @show L, Q
       end
(L, Q) = (5, Bool[0, 0, 0, 0, 0])
(5, Bool[0, 0, 0, 0, 0])

This is what the MVector macro does:

macro MVector(ex)
    static_vector_gen(MVector, ex, __module__)
end

And this is what static_vector_gen does to :comprehension expressions like the example:

    elseif head === :comprehension
        #= omitted some input validation =#
        ex = ex.args[1]
        #= omitted some input validation =#
        rng = Core.eval(mod, ex.args[2].args[2])
        exprs = (:(f($j)) for j in rng)
        return quote
            let
                f($(esc(ex.args[2].args[1]))) = $(esc(ex.args[1]))
                $SV{$(length(rng))}($tuple($(exprs...)))
            end
        end

rng = Core.eval(mod, ex.args[2].args[2]) evaluates 1:L in the global scope because it needs a preexisting value while still parsing the let expression to put a number of arguments into the tuple call jling showed. This also causes problems if the global value would be instantiated too late, like if this were a begin block defining L before a @MVector call. This is documented behavior, per the docstring for @SArray:

 2. comprehensions
       │ Note
       │
       │ The range of a comprehension is evaluated at global scope by the macro, and must be made of
       │ combinations of literal values, functions, or global variables.

The most direct Github issue for local variables in comprehension ranges is #26, but it was closed in favor of the wider #97. The workaround given there is to skip the macro:

julia> let L = 5, Q = MVector{L}(false for i in 1:L)
       @show L, Q
       end
(L, Q) = (5, Bool[0, 0, 0, 0, 0])
(5, Bool[0, 0, 0, 0, 0])
3 Likes