... | ... | @@ -7,12 +7,16 @@ This page summarises our current proposal for packages in GHC. |
|
|
A vexed question in the current design of Haskell is the issue of whether a single program can contain two modules with the same name. Currently that is absolutely ruled out, and as a result packages are fundamentally non-modular: every package must use a distinct space in the global namespace.
|
|
|
|
|
|
|
|
|
There are two quite separate issues, addressed in the following two sections. But before we start, note that we take for granted the following
|
|
|
There are two quite separate issues, addressed in "Question 1", "Question 2" below. First we give assumptions.
|
|
|
|
|
|
- Each package has a globally-unique name, organised by some social process
|
|
|
## Assumptions
|
|
|
|
|
|
|
|
|
This assumption is deeply built into Cabal, and lots of things would need to change if it wasn't met.
|
|
|
Before we start, note that we take for granted the following
|
|
|
|
|
|
- Each package has a globally-unique name, organised by some social process. This assumption is deeply built into Cabal, and lots of things would need to change if it wasn't met.
|
|
|
|
|
|
- Module names describe *purpose* (what it's for, e.g. `Data.Bits`), whereas package names describe *provenance* (where it comes from, e.g. `"gtkhs"`). We should not mix these two up, and that is a good reason for not combining package and module names into a single grand name. One quite frequently wants to globally change provenance but not purpose (e.g. compile my program with a new version of package "foo"), without running through all the source files to change the import statements.
|
|
|
|
|
|
## Question 1: Can two different packages contain a module with the same module name?
|
|
|
|
... | ... | @@ -81,49 +85,114 @@ That would presumably get the most recent installed incarnation of the `base` pa |
|
|
|
|
|
The exact syntax is unimportant. The important thing is that the programmer can specify the package in the source text.
|
|
|
|
|
|
## Alternative: the Packages space
|
|
|
|
|
|
If we adopt the idea that an import statement can specify the source package, several design choices arise:
|
|
|
|
|
|
### Is the 'from \<package\>' compulsory?
|
|
|
|
|
|
|
|
|
If you want to import A.B.C, a module exported by package "foo", can you say just `import A.B.C`, or must you say `import A.B.C from "foo"`?
|
|
|
|
|
|
|
|
|
We think of this as rather like the question "If you import f from module M, can you refer to it as plain "f", or must you refer to it as "M.f"? The answer in Haskell 98 is that you can refer to it as plain "f" so long as plain "f" is umambiguous; otherwise you can use a qualified reference "M.f" to disambiguate.
|
|
|
|
|
|
|
|
|
We propose to adopt the same principle for imports. That is, you can say "`import A.B.C`" so long as that is umambiguous (meaning that there is only one module A.B.C exported by any installed package). If the reference to A.B.C is ambiguous, you can qualify the import by adding "`from "foo"`".
|
|
|
|
|
|
### Package versions
|
|
|
|
|
|
|
|
|
We probably want some special treatment for multiple versions of the same package. What if you have both "foo-3.9" and "foo-4.0" installed, both exporting A.B.C? This is jolly useful when you want to keep install new packages, but keep old ones around so you can try your program with the older one. So we propose that this is not regarded as ambiguous: importing A.B.C gets the latest version, unless some compiler flag (-hide-package) takes it of the running.
|
|
|
|
|
|
### Importing from the home package
|
|
|
|
|
|
|
|
|
If A.B.C is in the package being compiled (which we call "the home package"), and in an exposed package, and you say `import A.B.C`, do you get an "ambiguous import" error , or does the current package override. And if the former, how can you say "import A.B.C from the current package"?
|
|
|
|
|
|
### The 'as P' alias
|
|
|
|
|
|
|
|
|
We propose to maintain the local, within-module "as P" alias mechanism unchanged. Thus:
|
|
|
|
|
|
```wiki
|
|
|
import A.B.C( T ) from "foo" as M
|
|
|
type S = M.T -> M.T
|
|
|
```
|
|
|
|
|
|
|
|
|
Here, the qualified name "M.T" refers to the T imported from A.B.C in package "foo".
|
|
|
|
|
|
### Qualified names
|
|
|
|
|
|
|
|
|
Perhaps every (exposed) module from every (installed) package should always be available via an import like
|
|
|
We propose that the default qualified name of an entity within a module is just the module name plus the entity name. Thus
|
|
|
|
|
|
```wiki
|
|
|
import Packages.Gtk-1_3_4.Widget.Button
|
|
|
import A.B.C( T ) from "foo"
|
|
|
type S = A.B.C.T -> A.B.C.T
|
|
|
```
|
|
|
|
|
|
|
|
|
That is, the module is name by a fully-qualified name involving its package name (already globally unique).
|
|
|
If you want to import multiple A.B.C's (from different packages) then perhaps they define different entities, in which case there is no problem:
|
|
|
|
|
|
```wiki
|
|
|
import A.B.C( T1 ) from "foo"
|
|
|
import A.B.C( T2 ) from "bar"
|
|
|
type S = A.B.C.T1 -> A.B.C.T2
|
|
|
```
|
|
|
|
|
|
|
|
|
(Tiresome side note: to make the package id look like a module name we may have to capitalise it, and change dots to underscores. And that could conceivably make two package names collide.)
|
|
|
But if they both export entities with the same name, there is no alternative to using the 'as M' mechanism:
|
|
|
|
|
|
```wiki
|
|
|
import A.B.C( T ) from "foo" as M1
|
|
|
import A.B.C( T ) from "bar" as M2
|
|
|
type S = M1.T -> M2.T
|
|
|
```
|
|
|
|
|
|
## Alterative: grafting
|
|
|
### Exporting modules from other packages
|
|
|
|
|
|
|
|
|
Some kind of 'grafting' or 'mounting' scheme could be added, to allow late binding of where in the module tree the is brought into scope. One might say
|
|
|
It is perfectly OK to export entities, or whole modules, imported from other packages:
|
|
|
|
|
|
```wiki
|
|
|
ghc -c Foo.hs -package gtk-2.3=Graphics.GTK
|
|
|
module M( f, g, module Q ) where
|
|
|
import A.B( f, g ) from "foo"
|
|
|
import X.Y.Z from "bar" as Q
|
|
|
```
|
|
|
|
|
|
### Syntax
|
|
|
|
|
|
|
|
|
Should package names be in quotes? Probably not. They have a well-defined syntax.
|
|
|
|
|
|
|
|
|
It's been suggested that one might want to import several modules from one package in one go:
|
|
|
|
|
|
to mount the `gtk-2.3` package at `Graphics.GTK` in the module name space. Outside
|
|
|
the package one would need to import `Graphics.GTK.M`, but within the package one just imports `M`. That way the entire package can be mounted elsewhere in the namespace, if desired, without needing to change or recompile the package at all.
|
|
|
```wiki
|
|
|
from "base" import
|
|
|
Prelude hiding (length)
|
|
|
Control.Exception
|
|
|
qualified Data.List as List
|
|
|
```
|
|
|
|
|
|
|
|
|
This would allow a single module to import modules from two different packages that happened to use the same name. It's not strictly a necessary feaure. If you want to
|
|
|
What we don't like about that is that it needs a new keyword "`from`". Perhaps all imports can start with the keyword `import`, and then we are free to use extra (context-specific) keywords. (Haskell already has several of these, such as `hiding`. Something like this:
|
|
|
|
|
|
- import module A from package P, and
|
|
|
- import module A from package Q into a single module M of a program,
|
|
|
```wiki
|
|
|
import from "base" {
|
|
|
Prelude hiding (length) ;
|
|
|
Control.Exception ;
|
|
|
qualified Data.List as List }
|
|
|
import from "foo" M( x, y )
|
|
|
```
|
|
|
|
|
|
|
|
|
you can always do this:
|
|
|
Here the layout is explicit, but perhaps the layout rule could apply.
|
|
|
|
|
|
- make a new module AP, that imports A and re-exports it all;
|
|
|
- compile AP with package P visible and Q hidden
|
|
|
- ditto for AQ
|
|
|
- make M say "import AP; import AQ".
|
|
|
|
|
|
Indeed, we could allow this multiple form even for ordinary imports:
|
|
|
|
|
|
The exact details of the mounting scheme, and whether it is done at
|
|
|
build time, at install time, or at compilation time, or all of the
|
|
|
above, are open to debate. We don't have a very fixed view. |
|
|
```wiki
|
|
|
import { A(f); B(g); C(S,T) }
|
|
|
``` |
|
|
\ No newline at end of file |