In recent versions of Cabal, there is a new
mixins:
field that allows us to make modified local "copies" of libraries mentioned in
the
build-depends:
field.
These "copies" differ from the originals in that their modules might have been renamed (module signatures might be renamed as well, but let's leave that for the next lesson).
In the example, we make two copies of the internal library foo
: one in which
module Foo
has been renamed to Bar
and another in which Foo
has been
renamed to Baz
:
mixins:
foo (Foo as Bar),
foo (Foo as Baz)
These modules are both imported by the module Lesson1
:
import qualified Bar
import qualified Baz
Compile in this folder with the command:
cabal build
Open a repl in the main library with
cabal repl lib:lesson1-renaming-modules
Open a repl in the convenience library with
cabal repl lib:foo
In the example code, the library foo
has an additional Foo.Extra
module
that we did not rename. What happens if we try to import it from Lesson1
?
import qualified Foo.Extra
We get an error! How come?
lib/Lesson1.hs:5:1: error:
Could not load module ‘Foo.Extra’
This is an important detail about how mixins:
works. If we make a local copy
of a library and rename some modules, all the other modules from the original
library that aren't explicily mentioned in the mixins:
entry become hidden.
The original form of the dependency is superseded by the altered copies.
What we can do? Mention that module in mixins:
, too:
mixins:
foo (Foo as Bar),
foo (Foo as Baz, Foo.Extra as Baz.Extra)
As we see, when making a "copy" of a library we can rename more than one module by separating the renamings with commas.
And now the previously hidden module can be imported:
import qualified Baz.Extra
We can rename modules from external package dependencies, not only modules of internal libraries.
For example, we can take the package bytestring
and rename the modules
Data.ByteString
and Data.ByteString.Lazy
to Bytes
and Bytes.Lazy
respectively:
mixins:
bytestring (Data.ByteString as Bytes, Data.ByteString.Lazy as Bytes.Lazy)
We wouldn't be able to import Data.ByteString.Builder
in our code however,
because it's not mentioned int the mixins:
entry!
-
This Stack Overflow answer about using 'mixins:' to avoid name collisions between modules of different packages.
mixins:
is a more principled alternative to the-XPackageImports
extension.