|Version 16 (modified by malcolm.wallace@…, 8 years ago) (diff)|
Module System oddities
There are inconsistencies in the current module system that cause confusion for users and complications for implementors. The issue is that while import, export, and hiding declarations have the same syntax, they have slightly different interpretations when it comes to names in the typespace.
In particular capital names are treated as types or classes in imports and exports but are treated as types, classes or value constructors in hiding clauses and there is no way to export just a constructor if it has the same name as a type.
Make bare capital names _always_ refer to value constructors, the presence of a subordinate list will mean it should be interpreted as a type or class.
so T will refer to a constructor always and T() will refer to a class or type always.
this same rule will be used uniformly in export,import, and hiding lists.
This will not only make everything consistant, but allow seperate decisions on whether to export a value or type constructor if they have the same name.
elements within a subordinate list will be intpreted as before, as either data constructors, class methods, or field names.
see section 9 of the following paper for more details:
There are a few things that should probably be clarified by the language definition dealing with field names and class methods, not that there is debate but they should be clearly specified:
- does exporting a class name and a method name seperately as a function allow it to be declared in instance declarations? or does the function name need to be exported as part of a subordinate list?
- the field name and function namespaces are different and export/import rules should take this into account, declaring fields creates _both_ a function and a field name. so should exporting the function also export the field name? or should the field name only be exportable via a subordinate list?
Some compilers distinguish these namespaces, others do not.
- We also may wish to specify recursive module behavior now that the work at formalizing the rules has been done in the previous paper. jhc and helium both implement the algorithm as given to good effect.
There has been past discussion on mailing lists about clarifying the import/export namespace in a different way. Each type or class constructor in an import or export list could be annotated with its namespace, e.g.
- import Foo (class Foo (Foo,Bar), data Baz())
I believe this would solve the same problems as the above proposal, but would be much less backward-compatible.
Permit Signatures in Export Lists
There is a good case to be made for permitting the inclusion of function signatures in the export list of a module. People often write them there anyway in comments, but the comments are not checked against the implementation, so changes can go unnoticed. There is also a good software engineering principle that says you should specify your interfaces as fully as possible. Signatures in export lists should be considered equivalant to signatures specified in the module itself at the top level for all purposes. If there are signatures in both the interface and the implementation, they should be identical (not just unifiable).
If we /required/ signatures in export lists (and always required a full export list too), this would solve the recursive module problem very simply. The export list would represent exactly the information currently contained in ghc's hs-boot files (and nhc98's hand-written .hi bootstrapping method).
Permit qualified exports
There was a long thread about this on the libraries list. Details to be filled in here. Outline:
- module GTK (..., qualified module GTK.Button as Button, ...) where
The user can import GTK and get all of the contents of GTK.Button imported qualified as Button.
Permit 'hiding' in export lists
- module Foo ( module Bar hiding (baz), Foo.baz ) where