To clarify, an explicit export:
module X (…) where …
An explicit import:
import X (…)
I would like to question the desirability of explicit exports and local imports in a production application.
I want to make two cases:
- That explicit exports are never necessary. Moreover, that explicit exports are harmful as they make checking of non-exported definitions impossible.
- That explicit imports are not necessary when importing a module from the same package.
By default, I make an easy claim that none are desirable since they incur mindless typing effort and thereby unfairly tax the programmer. Let us then consider the justifications for their use despite that.
When there are no explicit exports, everything is exported from a module. Recall a case when this is disadvantageous: abstract types. The values of abstract types must only be obtained via smart constructors. So their definitions should not be made available. Explicit exports may provide that.
However, there is another practice: putting dangerous definitions of the supposedly abstract type
X into a module
X.Internal, then importing them to module
X and defining smart constructors there. By default, a module only exports the definitions defined in itself — there are no re-exports. So, a user importing
X cannot invoke unsafe constructors from
X.Internal, and they know better than to import the dangerous module directly.
In the former case above, the internal definitions remain out of reach for a test suite. In the latter case, they may be freely checked as needed.
Recall the scenario in which explicit imports are useful.
- A module
"p" Xfrom package
pimports a module
"q" Yfrom package
- The package
qbumps the third version number and exports a definition
Y.dwhich name coincides with an already defined definition
If imports are explicit, nothing happens. The maintainers of
pare safe if they set a restriction as weak as
q ^>= 0.0.
If imports are implicit, there would be a clash of names if
pis built against
q v0.0.1, but the build would pass if it is built against a less recent version
The maintainers of
pmight not even notice that the package does not build in some cases. When they do, they would have to set a restriction
q ^>= 0.0.0
But surely there is only one version to build against if the two modules reside in the same package. So the overlapping names will necessarily result in an error that would immediately be rectified. It is no different from any other compile time error.