Why does Julia require a . for broadcasting?

In Fortran and some other languages, you can write exp(x) whether x is a scalar or an array. In Julia, you need to write exp.(x) if x is an array. What is the benefit of requiring the dot?

2 Likes

There are plenty of functions that would be ambiguous, such as multiplication between two matrices of the same shape – do you want that to be matrix multiplication or elementwise? You need both for e.g. convolutional neural networks. Languages like Python with numpy generally make those choices on an ad-hoc basis, and avoid ambiguity by assigning multiple operators or just not letting you broadcast most functions.

Julia gives you the ability to broadcast any function, and has the programmer explicitly specify when you want to broadcast in order to resolve the ambiguity.

ETA: making broadcasting part of the syntax also allows certain optimizations, check out More Dots: Syntactic Loop Fusion in Julia

23 Likes

There is a well defined function usually called “exponential” of a matrix. It is not equal generally to the exponential of each element of the matrix. You can see this:

julia> a = rand(10,10)
julia> exp(a) == exp.(a)
false

If exp(a) did the exponential of every element of the matrix, how would you express the matrix exponentiation? You would then have to define some mat_exp which would lose many of the advantages that multiple dispatch brings us.

Oh! @Satvik is a much faster typer!

13 Likes

I would say that this kind of disambiguation is a useful side effect of requiring dots for broadcasting functions like exp, but it was not the primary motivation. The primary motivations were:

  1. You want the caller to decide what functions to apply elementwise, and it should work for any function. The function implementor should not need to decide this in advance, as explained here.

  2. Having the caller indicate elementwise functions syntactically allows us to guarantee that nested elementwise calls are “fused” into a single loop without temporary arrays, as explained here. This is not a mere micro-optimization—fusion can have order-of-magnitude effects on performance and memory usage.

In early versions of Julia , functions like exp and sqrt did operate elementwise on array arguments, and we had separate functions expm and sqrtm for the “matrix algebra” versions (similar to Matlab and Numpy). After dot broadcasting was introduced in Julia 0.6, the latter functions could be renamed to exp and sqrt as a happy side effect.

49 Likes

Can’t overstate how much how a great decision that was. I’m regularly amazed when writing plot(some_complicated_function.(1:N)). In Matlab I had to constantly worry about the shape of the input to a function whenever I thought I could want to apply it elementwise later.

20 Likes

14 posts were split to a new topic: When does exp(A) ≈ exp.(A)?