Consider the following scenario:
do_something( v :: Vector{ T } ) where { T <: Integer } = println( "v = $v" )
function d_dep( d :: Integer )
axis_iters = fill( -1:1, d )
for ig in Iterators.product( axis_iters ... )
g = [ ig ... ]
do_something( g )
end
end
This is a model of what I am doing in another code, and does what I want if I provide a positive integer argument to d_dep:
julia> include( "nd.jl" )
d_dep (generic function with 1 method)
julia> d_dep( 1 )
v = [-1]
v = [0]
v = [1]
julia> d_dep( 2 )
v = [-1, -1]
v = [0, -1]
v = [1, -1]
v = [-1, 0]
v = [0, 0]
v = [1, 0]
v = [-1, 1]
v = [0, 1]
v = [1, 1]
julia>
Unfortunately d=0 means something in this case, and that's where things go pear-shaped:
julia> d_dep(0)
ERROR: MethodError: no method matching do_something(::Vector{Any})
Closest candidates are:
do_something(::Vector{T}) where T<:Integer
@ Main ~/julia/test/nd.jl:1
Stacktrace:
[1] d_dep(d::Int64)
@ Main ~/julia/test/nd.jl:9
[2] top-level scope
@ REPL[4]:1
julia>
The problem as I understand it is that when you apply the splat operator to the array axis_iters it gets expanded to a empty list from which Iterators.Product has nothing to get a type from, hence Vector{Any}. So two questions:
Currently I have a
if d == 0ind_dep. This is ugly. Is there a neater way to deal with the zero d case, or the whole structure in general? If it helps d should be positive semi-definite.Actually I don't really understand why when
d=0the loop is executed at all. Why is it - is Julia like Fortran66 was alleged to be (but wasn't) in that it was mandated that all loops have at least 1 trip? [ In F66 zero trip loops were actually implementation defined ]
The result of
Iterators.product()is a zero-dimensional iterator. In Julia a zero-dimensional iterators (things likeArray{Int, 0}) are implemented to behave like a scalarAnd you can see that you can iterate over a scalar:
So it should not be that surprising that you can iterate over a zero-dimensional
Array.This is basically a language design decision, made (AFAIK) to make some broadcasting cases like
[0, 1, 2] .+ 1work consistently. You can read more here.As for making the code work, I see two options:
Always make
typeof(g) == Vector{Int}, for example:Or add another
do_somethingmethod to catch thed==0case: