Best practice in package globals

I’m developing a package that has a couple of settings that are “global” to the package. Is there a best practice for this kind of thing?

At the moment I have some getters and setters but should I use ENV, which would allow use of withenv? Something like

ENV[PACKAGENAME_SETTING] = true

Constant Refs are often used for this:

const VALUE_A = Ref(42)
const VALUE_B = Ref("auto")
const VALUE_C = Ref(true)

function f(x)
    if VALUE_C[]
        @info VALUE_B[]
    end
    return 2 * x + VALUE_A[]
end

Since the Refs are constant, the function is type-stable. However, you can still change the values the Refs hold:

julia> f(5)
[ Info: auto
52

julia> VALUE_B[] = "manual"
"manual"

julia> VALUE_A[] = 142
142

julia> f(5)
[ Info: manual
152
2 Likes

Is there a usual way of exposing these to package users?

Functions are just fine IMHO:

export set_value_a
set_value_a(x::Integer) = VALUE_A[] = x
2 Likes

I would just use a custom struct:

@kwdef mutable struct PackageSettings
     a::Float64 = 1.0
     b::Int = 1
end

const package_settings = PackageSettings()

Then the user can do:

package_settings.a = 2.0

or one can define some setter function to make it prettier.

2 Likes

Preferences.jl ?

4 Likes

slaps forehead of course there’s a great package that solves this problem!

This thread piqued my interest since I ran into this need recently as well.

Can somebody explain to me the advantage of

const VALUE_A = Ref(42) compared to VALUE_A::Int = 42

Now, I do understand prior to 1.8, the second approach wasn’t possible. Besides that, I would be curious what the advantage might be?

Edit: I found this stackoverflow post which seems to imply they are equivalent (at least for the simple test in the post): python 3.x - Julia performance : use Ref()? - Stack Overflow. Though if there is an advantage one way or another, I would still be interested in hearing!

1 Like