Newly defined getindex() behaves differently in REPL and a function


#1

I need to deal with tuples of tuples a lot. They are specifically of type NTuple{3,NTuple{2,Int}}; in other words, each inner tuple has two integers and the outer tuple has three such tuples, like t = ((3,4), (5,6), (7,8)).

Also, I frequently need to construct a length-3 tuple by taking one integer per inner tuple. For example, from the above t I construct (4,5,8) by taking the 2nd entry from the first inner tuple, 1st entry from the second inner tuple, and 2nd entry from the third inner tuple.

Because I perform this operation frequently, I defined a new getindex function as a convenience function. The goal was to perform the above operation by t[2,1,2]. The new getindex implementation is as follows, and it seemed to work well in REPL:

julia> Base.getindex(t::NTuple{3,NTuple{2,Int}}, i::Int, j::Int, k::Int) = (t[1][i], t[2][j], t[3][k])

julia> t = ((3,4), (5,6), (7,8))
((3,4),(5,6),(7,8))

julia> t[2,1,2]
(4,5,8)

However, if I use this new getindex inside some function, it suddenly starts returning only the first two entries of the constructed length-3 tuple:

julia> test(t) = t[2,1,2]
test (generic function with 1 method)

julia> test(t)
(4,5)

Am I doing something wrong? Should I file an issue for this? This happens both in Julia v0.5 and v0.6.


#2

I can reproduce your problem. At first glance, it looks like a bug.


#3

Thanks for the confirmation! I filed an issue: https://github.com/JuliaLang/julia/issues/20733.


#4

Running test(t,i,j,k) = Base.getindex(t,i,j,k) (after the above) also yields a function that returns a length-2 tuple. Comparing the two methods using code_llvm shows that the lines that generate the third element of the tuple in Base.getindex are gone in test.

A simple work-around seems to be to wrap the Tuple in your own type. (Maybe this eliminates some optimizations that are specific to the Tuple type?) For example, with t and test defined as above:

julia> type mytype
         x::typeof(t)
       end

julia> my_t = mytype(t)
mytype(((3, 4), (5, 6), (7, 8)))

julia> Base.getindex(t::mytype, i::Int, j::Int, k::Int) = (t.x[1][i], t.x[2][j], t.x[3][k]);

julia> my_t[2,1,2]
(4, 5, 8)

julia> test(my_t)
(4, 5, 8)