|
| 1 | +.. sectnum:: |
| 2 | + |
| 3 | +**Module naming conventions for GHC base libraries** |
| 4 | + |
| 5 | +Background and motivation |
| 6 | +=========================== |
| 7 | +The accepted `Proposal #51: GHC base libraries <https://github.com/haskellfoundation/tech-proposals/blob/main/proposals/accepted/051-ghc-base-libraries.rst>`_ |
| 8 | +defines the following libraries: |
| 9 | + |
| 10 | +* ``base``: |
| 11 | + |
| 12 | + * The foundational library on which the rest of the Haskell ecosystem is based. |
| 13 | + * Its API is carefully curated by the `Core Libraries Committee <https://github.com/haskell/core-libraries-committee>`_, and is kept rather stable. |
| 14 | + * Depends on ``ghc-internal`` (and ``ghc-prim`` etc), but *not* on ``ghc-experimental``. |
| 15 | + * Major version bumps are at the Core Libraries Committee's discretion. |
| 16 | + |
| 17 | +* ``ghc-experimental``: |
| 18 | + |
| 19 | + * The home of experimental extensions to GHC, usually ones proposed by the |
| 20 | + `GHC Steering Committee <https://github.com/ghc-proposals/ghc-proposals/>`_. |
| 21 | + |
| 22 | + * Functions and types in here are usually candidates for later transfer into ``base``. But not necessarily: if a collection of functions is not adopted widely enough, it may not be proposed for a move to `base`. Or it could move to another library entirely. |
| 23 | + |
| 24 | + * It is user-facing (user are encouraged to depend on it), but its API is less stable than ``base``. |
| 25 | + |
| 26 | + * Depends on ``base``. |
| 27 | + |
| 28 | + * Likely to have a major version bump with each GHC release. |
| 29 | + |
| 30 | +* ``ghc-prim, ghc-internal`` (and perhaps others; it's an internal GHC implementation decision): |
| 31 | + |
| 32 | + * Define functions and data types used internally by GHC to support the API of ``base`` and ``ghc-experimental``. |
| 33 | + |
| 34 | + * These libraries come with no stability guarantees: they may change at short notice. |
| 35 | + * Certain to have a major version bump with every GHC release. |
| 36 | + |
| 37 | +In addition we already have: |
| 38 | + |
| 39 | +* ``ghc``: this library exposes GHC as a library, through the (currently ill-defined) GHC API. |
| 40 | + |
| 41 | +All these libraries follow the Haskell Package Versioning Policy (PVP). The reader is encouraged |
| 42 | +to consult `Proposal #51: GHC base libraries <https://github.com/haskellfoundation/tech-proposals/blob/main/proposals/accepted/051-ghc-base-libraries.rst>`_ for more background and rationale for this library structure. |
| 43 | + |
| 44 | +The question arises of *what module names should be used*. For example, suppose that all three exposed a module called ``Data.Tuple``. In principle that would be fine -- GHC allows you |
| 45 | +to use the package name in the ``import`` statement, to disambiguate. But it's *extremely* confusing. This proposal articulates a set of conventions to |
| 46 | +help us design module names. |
| 47 | + |
| 48 | +The proposal |
| 49 | +============ |
| 50 | + |
| 51 | +This proposal is split into four sub-proposals for easier discussion. Each sub-proposal builds on the |
| 52 | +earlier ones -- they are increments, not alternatives. |
| 53 | + |
| 54 | +The goals of this proposal are deliberately limited to establish naming conventions. We do not propose |
| 55 | +any changes to ``ghc`` or to ``cabal``. |
| 56 | + |
| 57 | +Proposal 1 |
| 58 | +----------- |
| 59 | + |
| 60 | +* Modules in ``base``, ``ghc-experimental``, ``ghc-prim``, ``ghc-internal`` etc should all have distinct names. |
| 61 | + |
| 62 | +That principle leads immediately to the question: what should those names be? Hence proposal 2. |
| 63 | + |
| 64 | +Proposal 2 |
| 65 | +----------- |
| 66 | + |
| 67 | +* Modules in GHC's internal libraries (``ghc-prim``, ``ghc-internal`` etc) should be of form ``GHC.Internal*``. |
| 68 | +* Modules in ``ghc-experimental`` should be of form ``*.Experimental``. |
| 69 | +* Modules in ``base`` should not have either of these forms. |
| 70 | + |
| 71 | +So example we might have |
| 72 | + |
| 73 | +* ``GHC.Internal.Bits`` in ``ghc-internal``, |
| 74 | +* ``Data.Bits.Experimental`` in ``ghc-experimental`` |
| 75 | +* ``Data.Bits``, and currently also ``GHC.Bits``, in ``base`` |
| 76 | + |
| 77 | +Why ``GHC.Internal.*`` for modules in ``ghc-internal``? Would ``GHC.*`` not be enough? Here's why: |
| 78 | + |
| 79 | +* ``base`` already has ``GHC.Bits``, and Proposal 1 stops us re-using the same module name in ``ghc-internal``. |
| 80 | + If we were starting from a blank sheet of paper we might have no ``GHC.*`` modules in ``base``, but there |
| 81 | + curently 138 such modules and it seems unlikely that we will ever remove all, or even most, of them from |
| 82 | + ``base``. |
| 83 | + |
| 84 | +* The prefix ``GHC.Internal`` serves as an additional clue to the importing module that this API is not stable. |
| 85 | + |
| 86 | +* Since ``ghc-internal`` is brand new, we can name its modules however we like. However, ``ghc-prim`` exists |
| 87 | + already and we may have to live with modules like ``GHC.CString`` in ``ghc-prim`` for a while. Perhaps |
| 88 | + we make the switch slowly over time, by introducing ``GHC.Internal.CString`` and deprecating ``GHC.CString``. |
| 89 | + |
| 90 | +Note that among the GHC implementation packages (``ghc-prim``, ``ghc-internal``, ``ghc-bignum`` etc) there |
| 91 | +is no expectation that the module name signals which package the module is in. It's just an internal |
| 92 | +implementation matter. |
| 93 | + |
| 94 | +Using a prefix for ``ghc-internal`` and a suffix for ``ghc-experimental`` may seem inconsistent, |
| 95 | +but it was a clear consensus from the discussion about the proposal: |
| 96 | + |
| 97 | +* ``Data.Tuple.Experimental``, for example, is an companion/extension of ``Data.Tuple``; some exports may move from one to the other. Many developers sort their imports alphabetically. Making this a suffix means all ``Data.Tuple``-related imports are next to each other. For example, one might prefer this:: |
| 98 | + |
| 99 | + import Control.Applicative |
| 100 | + import Control.Applicative.Experimental |
| 101 | + import Control.Arrow |
| 102 | + import Data.Tuple |
| 103 | + import Foreign.C |
| 104 | + import Foreign.C.Experimental |
| 105 | + |
| 106 | + to this:: |
| 107 | + |
| 108 | + import Control.Applicative |
| 109 | + import Control.Arrow |
| 110 | + import Experimental.Control.Applicative |
| 111 | + import Experimental.Foreign.C |
| 112 | + import Data.Tuple |
| 113 | + import Foreign.C |
| 114 | + |
| 115 | + This pattern, of a module in ``ghc-experimental`` that is closely related to one in ``base`` seems likely to be common. |
| 116 | + |
| 117 | +* On the other hand, GHC-internal modules are often unrelated to the naming |
| 118 | + scheme of ``base``. Here a prefix feels more appropriate. Moreover using a |
| 119 | + prefix aligns with current practice: the ``GHC.*`` convention is extensively |
| 120 | + used in the GHC-internal modules currently in ``base``, and ``ghc-prim``, as |
| 121 | + well as the modules that implement GHC itself. |
| 122 | + |
| 123 | +Proposal 3 |
| 124 | +----------- |
| 125 | + |
| 126 | +The current ``base`` API exposes many modules starting with ``GHC.*``, so the proposed conventions could only |
| 127 | +apply to *new* modules. |
| 128 | + |
| 129 | +* Over time, and only with the agreement and support of the Core Libraries Committee, we may remove some ``GHC.*`` modules |
| 130 | + from ``base``, especially ones that are barely used, or are manifestly "internal" (i.e. part of the implementation |
| 131 | + of other, more public functions). |
| 132 | + Of course there would be a significant deprecation cycle, to allow client libraries to adapt. |
| 133 | + |
| 134 | +Proposal 3 only expresses a direction of travel. We will have to see what the CLC's attitude is, |
| 135 | +and what the Haskell community thinks. Anything that disturbs the API of base needs to be considered |
| 136 | +rather carefully. |
| 137 | + |
| 138 | + |
| 139 | +Proposal 4 |
| 140 | +------------ |
| 141 | + |
| 142 | +All of the modules in package ``ghc`` currently start with ``GHC.*`` which |
| 143 | +(currently correctly) signals that they are part of GHC's internals. |
| 144 | + |
| 145 | +As part of the GHC API redesign (a HF project in its own right, currently stalled) it would be very helpful |
| 146 | +to identify a (multi-module) stable API for package ``ghc``. In that way, users of package ``ghc`` |
| 147 | +could know whether |
| 148 | +they are using a curated, relatively-stable API function, or reaching deep into GHC's guts and using |
| 149 | +a random fuction whose name or type, or very existence, might change without warning. Hence: |
| 150 | + |
| 151 | +* The public API of package ``ghc`` (GHC as a library) should have modules whose names clearly distinguish them |
| 152 | + from internal modules. |
| 153 | + |
| 154 | +For example, the public API could have modules of form ``GhcAPI.*``, or ``GHC.API.*``, or ``Language.Haskell.GHC.*`` or something else. The specifics are a matter for the future GHC API working group. |
| 155 | + |
| 156 | + |
| 157 | + |
| 158 | +Timescale |
| 159 | +========== |
| 160 | +The first release of GHC with ``ghc-experimental`` and ``ghc-internal`` will be GHC 9.10, which expect to |
| 161 | +release in early 2024. It would be good to establish naming conventions for modules well before this date. |
| 162 | + |
| 163 | +Example lifecycle |
| 164 | +=================== |
| 165 | + |
| 166 | +By way of example, consider the ``HasField`` class, which supports overloaded record fields. |
| 167 | +It is currently defined in ``base:GHC.Records``, which is an odd module to have to import. |
| 168 | +Moreover there is |
| 169 | +more than one GHC proposal that suggest changes to its design (e.g. see `GHC Proposal 158 <https://github.com/ghc-proposals/ghc-proposals/blob/master/proposals/0158-record-set-field.rst>`_); it is not nearly as stable as most of ``base`` |
| 170 | + |
| 171 | +If ``ghc-experimental`` had existed we would have put it in ``ghc-experimental:Data.Records.Experimental``. |
| 172 | +That would have made it clear that the design of overloaded records still evolving. |
| 173 | +Once the design becomes settled and stable, it could move to ``base``, perhaps in a module like ``Data.Records``. |
| 174 | + |
| 175 | +Other similar examples include |
| 176 | + |
| 177 | +* The tuple proposal of `GHC Proposal 475 <https://github.com/ghc-proposals/ghc-proposals/blob/master/proposals/0475-tuple-syntax.rst>`_ |
| 178 | +* `GHC Proposal 330 (Decorate exceptions with backtrace information) <https://github.com/bgamari/ghc-proposals/blob/stacktraces/proposals/0000-exception-backtraces.rst>`_ proposes significant new additions to the API of exceptions. |
| 179 | + |
| 180 | +Alternatives |
| 181 | +============== |
| 182 | +* We could dispute Proposal 1: one could imagine deliberately naming modules in ``ghc-experimental`` with the |
| 183 | + same module name as their eventual expected (by someone) home in ``base``. The goal would be to reduce impact if and when |
| 184 | + the module moves from ``ghc-experimental`` to ``base``. For example, we might add ``Data.Tuple`` to ``ghc-experimental`` containing the new type constructors ``Tuple2``, ``Tuple3`` etc that are proposed in `GHC Proposal 475 <https://github.com/ghc-proposals/ghc-proposals/blob/master/proposals/0475-tuple-syntax.rst>`_. However: |
| 185 | + |
| 186 | + * In the meantime there are two modules both called ``Data.Tuple``. This is bad. Which one does ``import Data.Tuple`` import? (Look at the Cabal file, perhaps?) How can I import both? (Package-qualified imports perhaps.) So it will really only help in the case of a brand-new module, not already in ``base``. |
| 187 | + * It loses the explicit cue, in the source code, given by ``import Data.Tuple.Experimental``. |
| 188 | + |
0 commit comments