Julia's array processing vs J

Whenever I read a laudatory comment re: Julia’s performance, I am frequently brought back to J’s performance claims, e.g. Vocabulary/ArrayProcessing - J Wiki (jsoftware.com)
Does anyone in this forum know of/use J, APL’S successor, or any of APL’s modern incarnations? Any comments J’s array processing vs Julia’s?

This is hard to answer in general. As far as I can tell, J is interpreted. Julia is compiled. Consequently, J will be quick to respond if you are using its built in compiled routines. In Julia, we generate machine code so I would expect to encounter some compiler latency. However, the resulting machine code would be expected to be faster and more efficient than an interpreter.

2 Likes

Of course I would want any performance comparison between the two done post-compilation in Julia. My sense reading J docs is that J is more array savvy than Julia, and knows (for example) how to deal correctly with numeric amounts, without the user having to interrogate such things. According to those docs, J knows how to scale (up) without necessitating that the user dig into any of J’s innards, as a Julia user/programmer might need to. As a simple example, when working in Julia and working with something as simple as a scalar, do I not have to know whether a number is an int, int32, int64, float32/64, and program accordingly? With J I do not have to know that.

I’m not sure what you mean—you can write generic code in Julia that works with any numeric type (without sacrificing performance). Being able to write type-generic code is a fundamental goal of most high-level languages these days.

I’ve never programmed in J, but the examples I’ve seen on places like Rosetta Code amaze me at how concise it can be (albeit quite difficult to read for outsiders). Seems like a fun language, if a bit esoteric.

4 Likes

Julia has a pretty comprehensive type conversion and promotion system. You often do not need to think explicitly about types.

julia> f(a, b) = 2a + b^2                                         
f (generic function with 1 method)                                                                                                  

julia> f(2,5)                                                     
29 
                                                                                                                                 
julia> f(2,5.5)                                                   
34.25   
                                                                                                                            
julia> f(2.45,5.5)                                                
35.15  
                                                                                                                             
julia> f(π, 0)                                                    
6.283185307179586
                                                                                                                   
julia> f(3//10, 2//10)                                            
16//25

See Conversion and Promotion · The Julia Language

Yet, Julia does type values.

julia> @code_typed f(2,5.5)                   
CodeInfo(                                     
1 ─ %1 = Base.mul_int(2, a)::Int64            
│   %2 = Base.mul_float(b, b)::Float64        
│   %3 = Base.sitofp(Float64, %1)::Float64    
│   %4 = Base.add_float(%3, %2)::Float64      
└──      return %4                            
) => Float64

The implicit typing helps compile the code. Here is the underlying LLVM IR which is then translated into your processor’s machine code.

julia> @code_llvm debuginfo=:none f(π, 0)     
define double @julia_f_430(i64 signext %0) #0 {                                             
top:                                            
%1 = mul i64 %0, %0                           
%2 = sitofp i64 %1 to double                  
%3 = fadd double %2, 0x401921FB54442D18      
 ret double %3                               
}

I had used kx’s kdb+ for nearly 10 years. Its power is its terse and domain specific set of operations that are highly optimized for working with financial market data.

If you’re just performing relatively simple operations on arrays, particularly time-series joins, you won’t find anything more productive than what can be written in 1 line of q/k.

The performance of vectorized operations is well optimized and on par with Julia, but once things get more complex and path-dependent, the overhead of an interpreted language and lack of flexible data-types become more troublesome.

4 Likes