Changes between Version 37 and Version 38 of Commentary/Packages/GhcPackagesProposal


Ignore:
Timestamp:
Oct 30, 2006 8:30:29 AM (7 years ago)
Author:
simonpj
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • Commentary/Packages/GhcPackagesProposal

    v37 v38  
    11[[PageOutline]] 
     2 
     3= Packages in GHC = 
    24 
    35This page summarises our current proposal for packages in GHC. (See also [wiki:GhcPackageNamespaces an extended proposal] to make namespaces first-class. The two proposals are mutually exclusive.) 
     
    57== The problem == 
    68 
    7 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.  
    8  
    9 There are two quite separate issues, addressed in "Question 1", "Question 2" below.  First we give assumptions. 
     9A vexed question in the current design of Haskell is the issue of whether a single program can contain two modules with the same name.  In Haskell 98 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.  
    1010 
    1111== Assumptions == 
     
    2525Then 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>}}}. 
    2626 
     27== The open question == 
     28 
    2729The remaining question is this: '''When you say {{{import A.B.C}}}, from what package does A.B.C come?'''.  Three alternatives are under consideration: 
    2830  * Plan A (GHC's current story) 
    2931  * Plan B: grafting.  An enhancement of plan A; see [wiki:PackageMounting Frederik Eaton's proposal] 
    30   * Plan C: optionally specify the package in the import.  An alternative to (B). 
     32  * Plan C: optionally specify the package in the import.  An alternative to (B), described in a [wiki:PackageImports separate page]. 
    3133 
    3234---------------------------- 
     
    4749 
    4850---------------------------- 
     51== Plan B: package mounting == 
     52 
     53This proposal is described by a [wiki:PackageMounting separate page]. 
     54 
     55---------------------------- 
    4956== Plan C: mention the package in the import == 
    5057 
    51 Another solution is to allow the programmer to specify the source package in the import line, something like this: 
    52 {{{ 
    53   import A.B.C from "base" ( map, filter ) 
    54 }}} 
    55 That would presumably get the most recent installed incarnation of the {{{base}}} package. If you want a particular version of the package, we could allow 
    56 {{{ 
    57   import A.B.C from "base-3.4" ( map, filter ) 
    58 }}} 
    59 The exact syntax is unimportant. The important thing is that the programmer can specify the package in the source text.  Note that this fundamentally conflicts with the second assumption we started with.  We were trying to avoid specifying "provenance" at the same time as "purpose", on the grounds that we wanted to avoid editing lots of source text when the provenance changed.  (And so it begs the question, if we need to edit the source anyway, why separate the syntax of packages from modules at all?) 
    60  
    61 If we adopt the idea that an import statement can specify the source package, several design choices arise: 
    62  
    63 === Is the 'from <package>' compulsory? === 
    64  
    65 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"}}}? 
    66  
    67 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. 
    68  
    69 We propose to adopt the same principle for imports. That is, an import with no package specified, such as "{{{import A.B.C}}}", means:  
    70  
    71    Find all modules A.B.C exported by all exposed packages, or the package or program being compiled. If there is exactly one such module, that's the one to import. Otherwise report "ambiguous import". 
    72  
    73 If the reference to A.B.C is ambiguous, you can qualify the import by adding "{{{from "foo"}}}". 
    74  
    75 === Package versions === 
    76  
    77 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 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. 
    78  
    79 In short, an installed package can be of two kinds: 
    80   * '''Exposed''': the package's modules populate the global module namespace, and can be imported without mentioning the pacckage name explicitly ({{{import A.B.C}}}).  Explicit "from" imports may be used to resolve ambiguity. 
    81   * '''Available''', but not exposed: the package can be used only by an explicit "from" import.  This is rather like "{{{import qualified M}}}, except at the package level.   
    82  
    83 Typically, if multiple versions of the same package are installed, then all will be available, but only one will be exposed. 
    84  
    85 GHC's command-line flags ({{{-hide-package}}}, {{{-package}}}) can be used to manipulate which packages are exposed, but typically an entire package or program will be compiled with a single set of such flags.  GHC does not curretly support in-module control, thus {{{ {-# OPTIONS_GHC -hide-package foo #-} }}}, and we do not propose to change that. 
    86  
    87 Simon suggested that an installed package might be hidden (so that it cannot be used at all) but I'm not sure why we need that. 
    88  
    89  
    90 === Importing from the home package === 
    91  
    92 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"?   
    93  
    94 One possibility is to reuqire the code to know its own package name, and mention that in the import. For exmaple, in a module that is being compiled as part package "foo", you'd say {{{import A.B.C from "foo"}}}.  What about modules that are part of the main program (not a package at all).  Perhaps you could then say {{{import A.B.C from "main"}}}. 
    95  
    96 Another way is to have a special package name meaning "the home package".  The special name could be 
    97  * "" 
    98  * "home" 
    99  * "this" 
    100  * this (with no quotes) 
    101  
    102 === The 'as P' alias === 
    103  
    104 We propose to maintain the local, within-module "as P" alias mechanism unchanged.  Thus: 
    105 {{{ 
    106    import A.B.C( T ) from "foo" as M 
    107    type S = M.T -> M.T 
    108 }}} 
    109 Here, the qualified name "M.T" refers to the T imported from A.B.C in package "foo". 
    110  
    111 === Qualified names === 
    112  
    113 We propose that the default qualified name of an entity within a module is just the module name plus the entity name.  Thus 
    114 {{{ 
    115   import A.B.C( T ) from "foo"  
    116   type S = A.B.C.T -> A.B.C.T 
    117 }}} 
    118 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: 
    119 {{{ 
    120   import A.B.C( T1 ) from "foo"  
    121   import A.B.C( T2 ) from "bar"  
    122   type S = A.B.C.T1 -> A.B.C.T2 
    123 }}} 
    124 But if they both export entities with the same name, there is no alternative to using the 'as M' mechanism: 
    125 {{{ 
    126   import A.B.C( T ) from "foo" as M1 
    127   import A.B.C( T ) from "bar" as M2 
    128   type S = M1.T -> M2.T 
    129 }}} 
    130  
    131 === Exporting modules from other packages === 
    132  
    133 It is perfectly OK to export entities, or whole modules, imported from other packages: 
    134 {{{ 
    135   module M( f, g, module Q ) where 
    136   import A.B( f, g ) from "foo" 
    137   import X.Y.Z from "bar" as Q 
    138 }}} 
    139  
    140 === Syntax === 
    141  
    142 Should package names be in quotes?  Probably yes, because they have a different lexcal syntax to the rest of Haskell.  ("foo-2.3" would parse as three tokens, "foo", "-",  and "2.3".   
    143  
    144 It's been suggested that one might want to import several modules from one package in one go: 
    145 {{{  
    146     from "base" import 
    147         Prelude hiding (length) 
    148         Control.Exception 
    149         qualified Data.List as List 
    150 }}} 
    151 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: 
    152  
    153 {{{  
    154     import from "base" { 
    155         Prelude hiding (length) ; 
    156         Control.Exception ; 
    157         qualified Data.List as List } 
    158     import from "foo" M( x, y ) 
    159 }}} 
    160 Here the layout is explicit, but the braces and semicolons could be avoided by making use of the layout rule as usual. 
    161  
    162 Indeed, we could allow this multiple form even for ordinary imports: 
    163 {{{ 
    164    import { A(f); B(g); C(S,T) } 
    165 }}} 
    166  
    167 It is clear from the above examples that the keyword {{{from}}} is redundant - the presence of a string literal (or special keyword to denote the home package) after the keyword {{{import}}} is sufficient to distinguish per-package imports from the ordinary shared-namespace imports, so the above could instead be written as 
    168 {{{ 
    169     import "base" 
    170         Prelude hiding (length) 
    171         Control.Exception 
    172         qualified Data.List as List 
    173     import "foo" M( x, y ) 
    174  
    175     import 
    176            A(f) 
    177            B(g) 
    178            C(S,T) 
    179 }}} 
    180  
    181 === Syntax formalised and summarised === 
    182  
    183 A possible syntax which covers everything in this proposal is therefore: 
    184  
    185    '''import''' [''package-name''] '''{''' ''import-specifier'' [''';''' ''import-specifier''] '''}''' 
    186  
    187 where ''package-name'' is a string literal or the keyword {{{home}}}, the ''import-specifier'' corresponds to everything that is currently allowed after the keyword {{{import}}}, and the braces and semicolons would be added by the layout rule. 
    188 {{{ 
    189     import "base" -- searches in "base" package only 
    190         Prelude hiding (length) 
    191         Control.Exception 
    192         qualified Data.List as List 
    193  
    194     import ""   -- searches in home package only 
    195         A.B.C 
    196  
    197     import P.Q.R -- searches in home + exposed packages 
    198 }}} 
     58This proposal is described by a [wiki:PackageImports separate page].