Personal tools

No export lists

From HaskellWiki

(Difference between revisions)
Jump to: navigation, search
(re-exporting identifiers)
m
Line 145: Line 145:
 
and export them explicitly
 
and export them explicitly
 
<haskell>
 
<haskell>
module Library (foo, bar) where ...
+
module Important (foo, bar) where ...
 
</haskell>
 
</haskell>
 
This way it is not clear, where <hask>foo</hask> and <hask>bar</hask> are from.
 
This way it is not clear, where <hask>foo</hask> and <hask>bar</hask> are from.
 
With the new syntax this is no longer the case.
 
With the new syntax this is no longer the case.
 
<haskell>
 
<haskell>
module Library where
+
module Important where
   
 
import A(foo*)
 
import A(foo*)
Line 157: Line 157:
   
   
[[Category:Syntax]] [[Category:Proposals]]
+
[[Category:Syntax]]
  +
[[Category:Proposals]]

Revision as of 12:10, 23 October 2007

Here I argue to remove export lists in Haskell in the long term and replace them by locally defined export modes. In the middle term both export declaration types could coexist.

1 Status quo

In Haskell 98 modules, all declared identifiers are exported by default.

module Important where
 
-- automatically exported
foo :: Int
foo = 2
That is, other modules can import and use identifiers like
foo
.

You have finer control by export lists. They enable you to keep implementation details private and prevent users of the module from relying on interna that might change in future.

module Important (foo, Number(One,Two,Three)) where
 
-- manually exported
foo :: Int
foo = 2
 
data Number = -- type is exported
     Zero  -- heretical things kept private
   | One   -- public
   | Two   -- public
   | Three -- public
   | Many  -- private

You can compare the export list with the definition modules of Modula-2 or the interface modules of Modula-3, and the module body with the implementation modules of the Modula dialects.

Even more, the documentation extraction tool Haddock allows to divide a module into sections, and it allows this to do it either in the module body

module Important (foo, Number(One,Two,Three)) where
 
{- * Important functions -}
 
{- | most important function -}
foo :: Int
foo = 2
 
{- * Important data types -}
 
{- | most important data type -}
data Number =
     Zero
   | One
   | Two
   | Three
   | Many

or in the export list.

module Important (
   {- * Important functions -}
   foo,
 
   {- * Important data types -}
   Number(One,Two,Three)) where
 
 
{- | most important function -}
foo :: Int
foo = 2
 
{- | most important data type -}
data Number =
     Zero
   | One
   | Two
   | Three
   | Many

2 Problems

The problem is that the export list duplicates data and the redundant information must be maintained. Whenever you add, remove, change the name of a function, you have to apply this change on the export list. If you comment out a malicious part of a module to get the rest compiled, you have to comment out parts of the export list, too. Haddock gives you the choice whether to define sections in the export list or the module body. However, what is the right choice?


3 Solutions

The language Oberon, the successor of Modula-2 by Niklaus Wirth, goes a different way. Like Haskell, Oberon has only one file per module. The interface file for a module is extracted by the Oberon compiler from the module file. Whether an identifier is exported is defined right at the declaration of that identifier by an asterisk. Adapted to Haskell this would look like

module Important where
 
{- * Important functions -}
 
{- | most important function -}
foo* :: Int
foo = 2
 
{- * Important data types -}
 
{- | most important data type -}
data Number* =
     Zero
   | One*
   | Two*
   | Three*
   | Many

Whenever you define a new identifier, you can decide on exporting just where the cursor is. The reader sees whether an identifier is exported just where it is introduced. Every change including deletion of a declaration automatically alters the exported data. Cute, isn't it?

Identifiers that are only re-exported (that is, imported from another module and exported as they are), may get a star attached in the import list, since this is the way, how the come into the module. Currently it is possible to import a bunch of identifiers anonymously by

import A
import B

and export them explicitly

module Important (foo, bar) where ...
This way it is not clear, where
foo
and
bar
are from.

With the new syntax this is no longer the case.

module Important where
 
import A(foo*)
import B(bar*)