Changes between Version 3 and Version 4 of Commentary/Packages/GhcPackagesProposal


Ignore:
Timestamp:
Jul 3, 2006 4:37:48 PM (8 years ago)
Author:
simonpj
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • Commentary/Packages/GhcPackagesProposal

    v3 v4  
    55A 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.  
    66 
    7 There are two quite separate issues. 
     7There are two quite separate issues, addressed in the following two sections 
    88 
    9 === Question 1: Can two different packages contain a module with the same module name? === 
     9== Question 1: Can two different packages contain a module with the same module name? == 
    1010 
    1111I now think that's unreasonable to answer 'no', because that means that EVERY module in EVERY package written by ANYONE must have different module names. That's like saying that every function must have different local variables, and is a serious loss of modularity.  I suspect that this is something about which we can all agree. 
    1212 
    13 To allow different packages to contain a module with the same name, the implementation must keep module names from different packages distinct.  If this was done, you could build a single program that used two packages that each used a ''hidden'' module M. 
     13The only sensible way to fix it is to relax the language design so that 
    1414 
    15 But what if two pacakges expose the same module M?  That takes us to Question 2. 
    16  
    17 === Question 2.  How are the (exposed) modules from an (installed) package brought into scope? === 
    18  
    19 That is, when you say "import M", from what package does M come? 
    20  
    21 Here GHC already has a fairly elaborate scheme (perhaps too elaborate). 
    22  * For a start, you may or may not have a package installed.   
    23  * Even if you do, the package may or may not be exposed by default (reasoning: you may want old versions of package X to be installed, but not in scope by default).   
    24  * Then, you can use the {{{-hide-package}}} flag to hide an otherwise-exposed package, and the {{{-package}}} flag to expose an otherwise-hidden package. 
    25  
    26 By manipulating these flags, you can expose package P1 when compiling module A (say), and expose P2 when compiling module B.  Then A and B could both import module M, which would come from P1 and P2 respectively. But: 
    27  * What if you wanted to import M from P1 and M from P2 into the ''same'' module? 
    28  * Compiling different modules with different flags in a way that affects the ''semantics'' (rather than, say, the optimisation level) seems undesirable. 
    29  
    30  
    31 == Our proposed design == 
    32  
    33 Simon Marlow and I have gradually become convinced that we have to fix this, and the only sensible way to fix it is to relax the language design so that 
    34  
    35  * a module name must be unique within its package (only) 
     15 * A module name must be unique within its package (only) 
    3616 
    3717That means that module A.B.C could exist *both* in package P1 and in P2. And both packages could be linked into the same program. Suppose for the moment that A.B.C is not exposed by both P1 and P2.  Then you would say simply: 
     
    3919  ghc --make Main -o app 
    4020}}} 
    41 Note the late binding here.  The authors of packages P1 and P2 didn't need to know about each other, and don't need to choose globally unique names. 
    42  
    43 Things are a bit more complicated if both P1 and P2 expose A.B.C, because then "{{{import A.B.C}}}" is ambiguous. Then it's unlikely that both P1 and P2 are exposed packages, and you'll need to bring them into scope explicitly: 
    44 {{{ 
    45   ghc -c -package P1 M1.hs 
    46   ghc -c -package P2 M2.hs 
    47   ...compile other modules... 
    48   ghc -o app M1.o M2.o ... -package P1 -package P2 
    49 }}} 
    50 To support {{{--make}}} in this situation we'd need to allow {{{-package}}} flags in the per-module {{{OPTIONS}}} pragmas.  ({{{ghc --make}}} already gathers those options together for the link step.) 
     21The authors of packages P1 and P2 didn't need to know about each other, and don't need to choose globally unique module names. 
    5122 
    5223The fundamental thing GHC needs to do is to include the package name into the names of entities the package defines.  That means that when compiling a module M you must say what package it is part of: 
     
    5627Then C.o will contain symbols like "{{{P1.A.B.C.f}}}" etc.  In effect, the "original name" of a function {{{f}}} in module {{{M}}} of package {{{P}}} is {{{<P,M,f>}}}. 
    5728 
    58 == Optional extra: the Packages space == 
     29But what if two packages '''expose''' the same module A.B.C?  That takes us to Question 2. 
     30 
     31=== Question 2.  How are the (exposed) modules from an (installed) package brought into scope? === 
     32 
     33That is, when you say "import A.B.C", from what package does M come? 
     34 
     35Here GHC already has a fairly elaborate scheme (perhaps too elaborate). 
     36 * For a start, you may or may not have a package installed.   
     37 * Even if you do, the package may or may not be exposed by default (reasoning: you may want old versions of package X to be installed, but not in scope by default).   
     38 * Then, you can use the {{{-hide-package}}} flag to hide an otherwise-exposed package, and the {{{-package}}} flag to expose an otherwise-hidden package. 
     39 
     40By manipulating these flags, you can expose package P1 when compiling module M (say), and expose P2 when compiling module N.  Then M and N could both import module A.B.C, which would come from P1 and P2 respectively. But: 
     41 * What if you wanted to import A.B.C from P1 and A.B.C from P2 into the ''same'' module? 
     42 * Compiling different modules with different flags in a way that affects the ''semantics'' (rather than, say, the optimisation level) seems undesirable. 
     43 * To support {{{--make}}} in this situation we'd need to allow {{{-package}}} flags in the per-module {{{OPTIONS}}} pragmas, which isn't currently supported.  ({{{ghc --make}}} already gathers those options together for the link step.) 
     44 
     45The obvious solution is to allow the programmer to specify the source package in the import line, something like this: 
     46{{{ 
     47  import A.B.C from "base" ( map, filter ) 
     48}}} 
     49That would presumably get the most recent installed incarnation of the {{{base}}} package. If you want a particular version of the package, we could allow 
     50{{{ 
     51  import A.B.C from "base-3.4" ( map, filter ) 
     52}}} 
     53The exact syntax is unimportant. The important thing is that the programmer can specify the package in the source text. 
     54 
     55 
     56== Alternative: the Packages space == 
    5957 
    6058Perhaps every (exposed) module from every (installed) package should always be available via an import like 
     
    6664(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.) 
    6765 
    68 == Optional extra: grafting == 
     66== Alterative: grafting == 
    6967 
    7068Some 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