Specific complaints about arrays are the design choice to not include dimensions in the type parameters. It means that simple errors only show up at runtime, sometimes hours into a simulation. The ability to specify not enough/too many indices is also a problem for the same reason.
It's hard to provide specific examples because a lot of the time I don't understand why something is happening. For example,
n = 10; [i for i=1:n]
gives an Array{Any,1}, but when I try to figure out why in the interactive prompt, [i for i=1:10]
gives an Array{Int64,1}. In my experience the Any version is slower, and they crop up all over, deep my programs. So I have to manually use n = 10; [i::Int64 for i=1:n]
The type system is generally quite nice and I like working with it a lot. But none of my colleagues know what it is and don't care how it works, they just want to add doubles together. So the fact that things like x = Array(1)
give error messages like ERROR: MethodError: `convert` has no method matching convert(::Type{Array{T,N}}, ::Int64)
This may have arisen from a call to the constructor Array{T,N}(...),
since type constructors fall back to convert methods.
Closest candidates are:
call{T}(::Type{T}, ::Any)
convert(::Type{Array{T,N}}, ::SharedArray{T,N})
convert{T,N}(::Type{Array{T,N}}, ::AbstractArray{T,N})
...
in call at essentials.jl:56
scares the living bejesus out of anyone who wants to simply use arrays without knowledge of types, parametric types, constructors, and the call and convert functions (not to mention that SharedArray and AbstractArray). All of this is too much abstraction for a normal scientist or engineer to want to have to deal with. What the error message really should just say is Missing type parameter in method: Array(<type>, <dimension>)
Arrays are implemented as abstract types and now constructors fall back to convert, which is all very clever and fits into the grand type system view, but the result is that the debug information is hugely complicated.As for the performance, I've been trying to implement my own FixedSizeArrays type thing, where arrays have dimensions as type parameters. My code for 1D looks like this:
immutable Float1D{nx}
data :: Array{Float64,1}
Float1D() = new(Array(Float64,nx))
function Float1D(xs::Array{Float64,1})
size(xs) == (nx,) || error("Size of initialization array ($(size(xs))) does not match type parameter ($nx)")
new(xs)
end
end
size{nx}(xs::Float1D{nx}) = (nx,)
getindex(xs::Float1D, i::Int) = xs.data[i]
setindex!(xs::Float1D, v::Real, i::Int) = xs.data[i] = v
And it's performance is much worse than the native arrays. I don't know why, since the methods seem simple enough to inline, but I'm sure there is a lot I'm missing. I think maybe it is partly because the Julia Array type and its methods seem to be implemented in C. Either way, having thought about this a lot and understand the compiler and type system reasonably well (for an end user) I still don't know how to get it to go faster. I think that is unreasonably complex for people who just want code to work fast.