Search code examples
arraystypesconstantsjuliatype-stability

Julia: Best practice for mutating type-stable arrays


This is my first try at Julia, so please forgive me if this sound trivial to you. My Julia code is already performing way better than my Python code, but I am left with a question concerning typing.

For a scientific program I am working with a multitude of arrays that are type-stable and of fixed dimensionality. The program aims to update these arrays by a mathematically non-trivial scheme in order to minimize an energy function. I have defined these arrays in the global scope by

const A = Array{Complex{Float32}}(dim)

where dim is the dimensionality. I noticed adding the const caused a my calculations to speed up considerably (x3 faster). Subsequently, the contents of these arrays are initialized and updated in functions by A[:] =....

Is defining type-stable arrays of fixed dimensionality as consts globally, and updating by accessing them as A[:] considered bad practice?

My best shot at an alternative method would be typing the input arguments of all my functions and passing a lot of variables around. Would this be more desirable?


Solution

  • My (subjective) opinion is that defining them as const and then mutating the contents is, by itself, not necessarily a bad practice. It's clear in Julia that the const declaration is about the variable-value binding, not the internals of the value.

    However, if the same variable A is used to hold disparate unconnected values (and not different forms of the same matrix, for eg. reduced forms), that's certainly bad practice. A[:] .= A .* 2 is fine, A[:] .= X is not.

    Also, having multiple global variables that are mutated in different places is usually a code smell, and often leads to subtle and not-so-subtle bugs. It also makes the code hard to reason about.

    How about encapsulating the variables in a single struct type, for eg.

    struct ArrayVars 
       A::Array{Complex{Float32}, dim}
       B::Array{Float64, dim}
       ...
    end
    

    and creating an instance of that in an init style function? (Hopefully you can come up with a better name for the type than ArrayVars, taking into account the semantics of the arrays involved.) Then, you could pass this single variable of this type to functions and manipulate the arrays inside it, instead of passing around a lot of variables to each function.