Exportall might be useful in some (limited) cases?

There are many good points against common use of exportall:

  1. possible name conflicts when importing from different packages
  2. with explicit export, we know what symbols are intended for internal uses only, and what are intended for external uses

However, these arguments might not be suitable for some specific cases.

I’m wring a somewhat large package for DFT, and I organize my code into submodules.
Since every submodule has its own namespace, import/export/using becomes something to be considered.

I’ve met two things for which exportall might be useful:

  1. Physical constants.
  2. type aliases.

Currently, I have a submodule called PhysicalConstants, and I’m left with three choices:

  1. manually export everything in PhysicalConstants
  2. manually import everything I use in every submodule that uses PhysicalConstants - nearly every submodule else
  3. using PhysicalConstants, then in my code, write something like PhysicalConstants.eV * PhysicalConstants.angstrom over and over and over again, or, somewhat better, a using PhisicalConstants as m then m.eV * m.angstrom - but let’s consider readability, a magic name like m is definitely mysterious, and any reasonble name, like consts or so, are somewhat long.

In my opinion, for this specific case, exportall functionality is quite handy and should not introduce any problems.
The main argument here is, physical constants should be somewhat unique, so they should not get involved into name conflicts. It will be ridiculous that you ever need two different planck_constants , if not for different unit systems.
However, we are now talking about import inside one package, between different submodules.
Inside a package, it is rational to keep to one unit system, and perform unit transform only in specific I/O functions. So there should only be one value for a physical constant, and there should not be any name conflicts.


ps: Off topic, but global variables are also commonly regard as bad, and many tend to declare “no global variables” in every post they met. However, for something like physical constants - which might be defined as macro in C - are there better, simple way to do this?

You can write

const h = 6.62607015e−34

and you don’t have to worry about it being global anymore as the compiler can infer its type (as it can’t change).

Shameless self-plug: did you see PhysicalConstants.jl?

1 Like

To be clear, non-constant globals are commonly regarded as bad. Constant globals are perfectly fine: Performance Tips · The Julia Language

2 Likes

Yes, I checked it when I began my project, and found it had rich features like different codata versions, uncertainty data and so on, which seemed to be an overkill, so I didn’t use it then.
But I’m considering to turn to it now.


Back to the main topic, I checked your repo and found constants are defined with macro constant and derived_constant. It seems that export is done in _constant_begin. It is somehow similar to the first proposed way, i.e., manually export everything?

Someone definitely have different ideas, can see this post

To be clear here, what I was referring to was constantly reading & writing those globals. The compiler can’t make that more efficient, even if it could in some circumstances when the variable would not be a global, because it should ensure that the value is actually being written to the global. This can remove a lot of optimizations using that variable. I’m not sure it always does, but that’s the mental model I’ve always been going with and which served me well so far. Reading/writing once isn’t that bad and unlikely to be performance critical anyway.

In my opinion, what matters more is not whether the variable is read/written once or constantly, but whether it is read-only, or can be changed. Physical constans, as discussed here, should be read-only, but may be read frequently.
I think that the compiler can do much to optimize read-only variables, but in Julia, it seems that we cannot inform compiler about this?
Mutable objects, whose reference are read-only, are harder to analyze and I don’t quite know.

Anyway, my main point is that global variables may sometimes be appropriate to use. Whether they have performance impact is a technical problem that is important in some cases and not important in others. Rejecting them anywhere without any thought is not wise.

You can export all symbols (or a subset) as follows:

1 Like

There is const for these and for immutable constants it’s absolutely fine to use them if you only ever read from them (they’ll be inlined in those cases). However, if the possibility of writing to them exists, the compiler may not always inline (with a drop in performance, due to having to look them up all the time). It’s a tradeoff that most of the time favors the “don’t be global” side, since people often want to write to them as well.