How to provide two versions of some quantities to the user. Can they unload a module?

Hi! I wrote this on the Slack but I think here may be a good fit.

I have a package that contains some physical constants (for example g, the acceleration of gravity). I provide units with the constants through Unitful.jl . But I want the user to be able to use the constants with units or without units

One option is to leave the user the burden of importing the module and defining all the unitless constants by hand at the beginning. But because my user is me, I found this annoying. What I thought is to have two submodules on my package. One contains the values with units and one without units.

module MyPackage
    module WithUnits
         export constantsWithUnits
    module NoUnits 
        export constantsWithNoUnits

So that the user can do at the beginning:

using MyPackage
using MyPackage.WithUnits


using MyPackage
using MyPackage.NoUnits

and get the constants with units or without them at will.

This seems to work, but then how can I change my choice after I used one of them already? This would be useful for example to run the unit tests with both of the choices.

What other design ideas come to mind?


You could bind a non-constant name to the module, but probably that cannot be recommended if you need these constants for performance critical code:

julia> module A
         export c
         c = 1

julia> module B
         export c
         c = 2

julia> using .A

julia> mymod = A

julia> mymod.c

julia> using .B

julia> mymod = B

julia> mymod.c

I think this may work, although I wanted to avoid having to qualify constants name with a module, e.g. instead of g having to write constants.g which makes it many times longer. I should rethink my design and keep an eye open on other packages to see how they do similar things.

This is something for which I’m also looking for a solution.
I was thinking more of another way, but maybe it’s not applicable to your case.

using Unitful
import PhysicalConstants.CODATA2018: c_0

Then define two methods that give back c_0:

speed_light( :: T ) where {T <: Number} = ustrip(c_0)
speed_light( ::Quantity{T,D,U}) where {T,D,U}  = Float64(c_0)

The first method gives just the value of c_0, the second adds the units:

julia> speed_light(1.0)

julia> speed_light(1u"m")
2.99792458e8 m s^-1

Now you could use this in your code to compute the frequency

julia>frequency(wavelength) = speed_light(wavelength)/wavelength
frequency (generic function with 1 method)

julia> frequency(200e-9)

1.49896229e15 s^-1

No need for two modules.
Would that work for you?

1 Like