I use Julia often, but mostly JuMP. I have incentivized the use of Julia in my laboratory. Today, one of my laboratory colleagues has said to me he used Julia to make a small program, and while he overall liked the language he found the inconsistency between row and column major to have made him lost some sanity and wasted considerable development time. I was confused because I do not make much use of matrices but this somewhat did not align with I had seen in many discussion about Julia. After 15~30 minutes I found where he got confused, and I kinda conceded the point (but I would like to hear you opinion about it). The problem is that two approaches that seem like they should work seamlessly do not work at all. In the examples below, we want to compute a dot product.
julia> m = [1 2 3; 4 5 6]
2Ă3 Array{Int64,2}:
1 2 3
4 5 6
julia> for row in eachrow(m)
row * [2, 2, 2]
end
As Vectors/Array{Any, 1}
are seen as columns, one would expect that to work, but instead you see an error message starting with:
ERROR: MethodError: no method matching *(::SubArray{Int64,1,Array{Int64,2},Tuple{Int64,Base.Slice{Base.OneTo{Int64}}},true}, ::Array{Int64,1})
What is kinda reasonable but then it is followed by a âclosest candidateâ for the multiplication operator that has two parameters each with literal 20 lines of type description (::LinearAlgebra.Adjoint{#s627,#s626} where #s626<:Union{DenseArray{T,2}, Base.ReinterpretArray{T,2,S,A} where S ...
).
If you instead do:
julia> col_factor = fill(2, 3, 1)
3Ă1 Array{Int64,2}:
2
2
2
julia> for row in eachrow(m)
row * col_factor
end
You get the much more legible error message saying: ERROR: DimensionMismatch("matrix A has dimensions (3,1), matrix B has dimensions (3,1)")
. However, this is also confusing because, in this case, the programmer has no reason to believe that eachrow
does not actually returns rows but columns, they may fist guess that they inverted the order of the dimensions in the fill
call or that the error is bubbling up in a place different from where the real mismatch happens.
So, was this intended? an oversight? or seems good in theory but there other more general issues that prevent changing this behavior? or I am missing something and one should not expect what my friend expected? Seems to me that it could be a subtle source of bugs.
To clarify even more, why:
julia> for row in eachrow(m); println(row); end
[1, 2, 3]
[4, 5, 6]
and not
julia> for row in eachrow(m); println(row); end
[1 2 3]
[4 5 6]