
Hi, I would like to suggest a change to Haskell prime's handling of imports. First, let me define a few terms: Qualified import: import qualified Data.Map [as Map] Closed-unqualified import: import Data.Map(Map, lookup) Open-unqualified import: import Data.Map I believe that the last type, open-unqualified is a really bad idea, and should be discouraged or even disallowed. It should definitely not be the default, like it is today. These are my reasons: A) Most importantly, reading code that has even a few open unqualified imports makes deciphering where names are coming from really difficult. The other two forms make it really easy. Code is read more often than it is written -- lets optimize for the reading case. B) Code that has open unqualified imports may break when new symbols are added to the libraries its importing. This means that libraries cannot even be considered backwards compatible if they retain semantics, but add new exported names. C) In my experience, Haskell modules can map their semantics to standard type-classes such as Monoid, Functor, Applicative, etc. This means that many Haskell modules can do without exporting many names. Sometimes, they can export no names at all (Only instances). This means that closed-unqualified imports often do just fine. When there are many exported names, qualified imports are good. ----------------- I think currently many modules are designed to be imported unqualified, and this is unfortunate. Haskell' libraries can fix this. For example, the various Monadic counterparts such as mapM, replicateM, etc could do without the "M" in their names, and one could use: import qualified Control.Monad as M M.for M.map and so on. Additionally, I think there are some strong sentiments against the choice of the function-composition dot as the qualified module name lookup symbol. It discourages people from using qualified imports. Some other symbol ought to be used, but its not clear which symbol is free. Perhaps if unicode operators are allowed, then function composition can move to the "right" symbol. I believe qualified imports should probably have this syntax: import Control.Monad as M Closed-qualified imports can remain in the same syntax. Open-qualified imports should probably be discouraged with a syntax like: import unqualified Control.Monad And symbol clashes with these should probably just always choose the overriding name. Additionally, it would be nice if open unqualified imported were considered quick&dirty enough for -Wall to warn that they generate name clashes or are more difficult to read, to further discourage them. Eyal

On Fri, Jan 16, 2009 at 4:42 PM, eyal.lotem@gmail.com
Hi,
I would like to suggest a change to Haskell prime's handling of imports.
First, let me define a few terms:
Qualified import: import qualified Data.Map [as Map]
Closed-unqualified import: import Data.Map(Map, lookup)
Open-unqualified import: import Data.Map
I believe that the last type, open-unqualified is a really bad idea, and should be discouraged or even disallowed. It should definitely not be the default, like it is today.
These are my reasons:
A) Most importantly, reading code that has even a few open unqualified imports makes deciphering where names are coming from really difficult. The other two forms make it really easy. Code is read more often than it is written -- lets optimize for the reading case.
B) Code that has open unqualified imports may break when new symbols are added to the libraries its importing. This means that libraries cannot even be considered backwards compatible if they retain semantics, but add new exported names.
C) In my experience, Haskell modules can map their semantics to standard type-classes such as Monoid, Functor, Applicative, etc. This means that many Haskell modules can do without exporting many names. Sometimes, they can export no names at all (Only instances). This means that closed-unqualified imports often do just fine. When there are many exported names, qualified imports are good.
-----------------
I think currently many modules are designed to be imported unqualified, and this is unfortunate. Haskell' libraries can fix this. For example, the various Monadic counterparts such as mapM, replicateM, etc could do without the "M" in their names, and one could use:
import qualified Control.Monad as M
M.for M.map
and so on.
Additionally, I think there are some strong sentiments against the choice of the function-composition dot as the qualified module name lookup symbol. It discourages people from using qualified imports. Some other symbol ought to be used, but its not clear which symbol is free. Perhaps if unicode operators are allowed, then function composition can move to the "right" symbol.
I believe qualified imports should probably have this syntax:
import Control.Monad as M
Closed-qualified imports can remain in the same syntax. Open-qualified imports should probably be discouraged with a syntax like:
Correction: Closed-unqualified imports can remain in the same syntax. Open-unqualified imports should probably be discouraged with a syntax like:
import unqualified Control.Monad
And symbol clashes with these should probably just always choose the overriding name.
Additionally, it would be nice if open unqualified imported were
imported -> imports
considered quick&dirty enough for -Wall to warn that they generate name clashes or are more difficult to read, to further discourage them.
Eyal

Eyal Lotem wrote:
B) Code that has open unqualified imports may break when new symbols are added to the libraries its importing. This means that libraries cannot even be considered backwards compatible if they retain semantics, but add new exported names.
This is not as uncommon as might sound and has happened a few times to me now, one example being hackage package yogurt failing to build on 6.10: Ambiguous occurrence `empty' It could refer to either `Data.IntMap.empty', imported from Data.IntMap at Network/Yogurt/Mud.hs:43:28-32 or `Text.Regex.Posix.empty', imported from Text.Regex.Posix at Network/Yogurt/Mud.hs:45:0-22 It's taught me to use qualified imports a lot more often. Martijn.

On Fri, 16 Jan 2009, eyal.lotem@gmail.com wrote:
I believe that the last type, open-unqualified is a really bad idea, and should be discouraged or even disallowed. It should definitely not be the default, like it is today.
You are not alone: http://haskell.org/haskellwiki/Import_modules_properly

On Fri, 16 Jan 2009, eyal.lotem@gmail.com wrote:
import qualified Control.Monad as M
M.for M.map
and so on.

On Friday 16 January 2009 9:42:46 am eyal.lotem@gmail.com wrote:
I think currently many modules are designed to be imported unqualified, and this is unfortunate. Haskell' libraries can fix this. For example, the various Monadic counterparts such as mapM, replicateM, etc could do without the "M" in their names, and one could use:
import qualified Control.Monad as M
M.for M.map
I don't think I can fully agree with this. The fooM functions are so named because their type is different in a fairly predictable way from ordinary foo functions. And there are, in fact, two different functions that could lay claim to M.map. One is named mapM, of course, but the other is liftM: liftM :: Monad m => (a -> b) -> m a -> m b Which is an implementation of the ordinary map using the methods of Monad. Similarly, Data.Traversable has two functions: mapM :: Monad m => (a -> m b) -> t a -> m (t b) fmapDefault :: Traversable t => (a -> b) -> t a -> t b So, do we end up with T.map is a monadic map, but T.mapDefault is an ordinary Functor map using the Traversable methods. There are also mapAccumL and mapAccumR, but those don't allow monadic functions like T.map, just pure functions like T.mapDefault (although, secretly it's T.map specialized to the state monad). Anyhow, if you have some easy way to view the types of these functions, that clears up their use quite a bit. However, the naming scheme is not purely due to "this is map from the Monad module we're going to import unqualified." There is some method to it. -- Dan

On Fri, Jan 16, 2009 at 06:42:46AM -0800, eyal.lotem@gmail.com wrote:
Closed-unqualified import: import Data.Map(Map, lookup)
One problem with this style is that you can get lots of conflicts from your VCS if you have multiple people working on the same module. Thanks Ian

Ian Lynagh wrote:
On Fri, Jan 16, 2009 at 06:42:46AM -0800, eyal.lotem@gmail.com wrote:
Closed-unqualified import: import Data.Map(Map, lookup)
One problem with this style is that you can get lots of conflicts from your VCS if you have multiple people working on the same module.
Right; in GHC we actively discourage the use of explict import lists (or closed-unqualified import to use the terminology of this thread). http://hackage.haskell.org/trac/ghc/wiki/Commentary/CodingStyle#Imports I find that the reasons not to use explicit import lists outweigh the reasons to use them, at least for code that I'm working on (rather than just reading). Ideally the import lists would be maintained automatically by an IDE, and would be intelligently handled by the VCS. Cheers, Simon

On Wed, 4 Feb 2009, Simon Marlow wrote:
Ian Lynagh wrote:
On Fri, Jan 16, 2009 at 06:42:46AM -0800, eyal.lotem@gmail.com wrote:
Closed-unqualified import: import Data.Map(Map, lookup)
One problem with this style is that you can get lots of conflicts from your VCS if you have multiple people working on the same module.
Right; in GHC we actively discourage the use of explict import lists (or closed-unqualified import to use the terminology of this thread).
http://hackage.haskell.org/trac/ghc/wiki/Commentary/CodingStyle#Imports
I find that the reasons not to use explicit import lists outweigh the reasons to use them, at least for code that I'm working on (rather than just reading).
Ideally the import lists would be maintained automatically by an IDE, and would be intelligently handled by the VCS.
This will work only if you exclusively import from modules of the same project, where you can choose identifiers to never clash, and external library modules where no functions are added anymore. Certainly for GHC this works since the compiler as basis tool must not depend on many libraries. However for me the situation is that I use many libraries, each maintained by only a few people. Within this kind of development name clashes are more likely than versioning conflicts. The only style that avoids both kinds of conflicts is the qualified import, which I try to use whereever possible.

On Wed, Feb 4, 2009 at 4:22 PM, Henning Thielemann
On Wed, 4 Feb 2009, Simon Marlow wrote:
Ian Lynagh wrote:
On Fri, Jan 16, 2009 at 06:42:46AM -0800, eyal.lotem@gmail.com wrote:
Closed-unqualified import: import Data.Map(Map, lookup)
One problem with this style is that you can get lots of conflicts from your VCS if you have multiple people working on the same module.
Right; in GHC we actively discourage the use of explict import lists (or closed-unqualified import to use the terminology of this thread).
http://hackage.haskell.org/trac/ghc/wiki/Commentary/CodingStyle#Imports
I find that the reasons not to use explicit import lists outweigh the reasons to use them, at least for code that I'm working on (rather than just reading).
Ideally the import lists would be maintained automatically by an IDE, and would be intelligently handled by the VCS.
This will work only if you exclusively import from modules of the same project, where you can choose identifiers to never clash, and external library modules where no functions are added anymore. Certainly for GHC this works since the compiler as basis tool must not depend on many libraries. However for me the situation is that I use many libraries, each maintained by only a few people. Within this kind of development name clashes are more likely than versioning conflicts. The only style that avoids both kinds of conflicts is the qualified import, which I try to use whereever possible.
Another solution would be an automated tool to add explicit import lists as part of the release process. Then you don't have to worry about maintaining them but once you do the final release, you know that it won't break if new functions are added to dependencies. Perhaps I will create such a tool sometime... Alex
participants (8)
-
Alexander Dunlap
-
Dan Doel
-
Eyal Lotem
-
eyal.lotem@gmail.com
-
Henning Thielemann
-
Ian Lynagh
-
Martijn van Steenbergen
-
Simon Marlow