Hi! The last two weeks I've seen two new packages that add suffixes to identifiers instead of relying on them being imported qualified to distinguish them from identifiers in other modules. This is not a new thing in Haskell community and there are examples of this practice in libraries shipped with GHC. It is also common in papers (for good reasons as we will see later). Atomic channels and variables under Control.Concurrent.* are examples of using a prefix as a namespacing tool. Let me reiterate the arguments [1,2] against this practice and also speculate why this practice is more common in Haskell than in e.g. Python, Java or Ruby.
* Cons of including a namespace prefix/suffix in identifiers 1. From experience these prefixes/suffixes tend to be short and non-descriptive, typically just one letter e.g. foldU or elemB. Very frequently used functions that every Haskell programmer is likely to use often can have shorter name as the cost of memorizing them is amortized over all their uses. Examples of short names that most Haskell programmers know by heart is map, fold*, etc. Given that your library won't see the same use as these functions your functions need more descriptive names (or in this case use a qualified import that makes them more descriptive e.g. Array.fold). 2. If your modules are imported qualified the suffix is redundant and thus wastes space. Consider for example foldU imported qualified from the module Data.Array as Array.foldU. Array.fold would have been better in this case. * Pros of using qualified imports 1. Your code will be more robust against additions to modules you depend on. Consider this snippet: import Some.Module -- An utility function that the author of the above module forgot to include. foo = ... Now the author of Some.Module releases a new version of his or her package which include `foo' and your code no longer compiles. If you have no imports on the form import Some.Module your package can specify more relaxed version dependencies on other packages [3]. 2. It's easier to see from where an identifier is imported. Just check the functions module prefix (e.g. Array in Array.foo). If you renamed the import using import Foo as F you might have to check the import list. * Explicit, unqualified imports An alternative to qualified imports that shares some of benefits is to import names unqualified but explicitly enumerate the function names e.g. import Some.Module (foo, bar) It is still not immediately obvious what module a name refers too when using this style (point 2 under pros above) but it is at least easier to find than when implicitly importing all names from a module. This is my current preference for infix operators as they look quite ugly qualified with a module name. It might also make sense if a few functions (e.g. parser combinators) are used a lot in the same module (e.g. an HTTP parser). * Why is this practice common in Haskell Here are some guesses: 1. It's common in papers. However, papers and libraries are quite different. The former usually build up a small vocabulary and having short names is a big win. Papers rarely make use of the module system at all. The latter are included as pieces of large programs and their names need to be adjusted accordingly. 2. It's the default. You have to add "qualified" to all your imports to make them qualified. In most language imports are qualified by default. I think the latter would have been a better choice but we have to live with the current design so bite the bullet and add those qualified keywords to your imports. 3. Lack of common interfaces. An example would be two different set implementations that essentially have the same interface but since there is no explicitly shared interface, defined using a type class, you sometimes end up with different names. The lack of type families might explain why e.g. collection classes don't share interfaces. 4. Haskell is a very expressive language. You can often write a whole function definition on one line! Adding those module qualifications makes your code slightly longer and it might just break your beautiful one liner into two lines. * Summary Whenever you write a library design it so it works well with qualified imports. That means leaving namespacing issues to the module system. Try to think of how code using your functions will look like if it uses them qualified. * References 1. http://www.haskell.org/haskellwiki/Import_modules_properly 2. http://www.haskell.org/haskellwiki/Qualified_names 3. See section 2 Version numbers - http://www.haskell.org/haskellwiki/Library_versioning_policy Cheers, Johan _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe