
In writing a large program, do people tend to just name all their functions differently, or do they make much use of qualified imports? I'm currently facing this design decision in starting my first significant Haskell project and I'd prefer to do whatever's conventional in the Haskell community. Personally, I'd probably veer towards all the qualified stuff, given that I'm the sort of person who never uses 'import' in Java, but then I have the question of how to name types that would otherwise be of the form Foo.Foo and look silly. (In Modula-3, Foo.T would be the traditional choice.) -- Mark

Mark Carroll writes:
In writing a large program, do people tend to just name all their functions differently, or do they make much use of qualified imports?
In my experience, qualified names are mostly used to eliminate conflicts rather than being used consistently on all symbols and people tend to avoid introducing conflicts within their code and between their code and the standard libraries. Some reasons for this include: 1) If you insist on qualifying all Prelude symbols, you get code like: 1 Prelude.+ 2 Prelude.* 3 foo n | n > 0 = ... -- should qualify > and 0 too... | Prelude.otherwise = ... 2) It's quite common to bundle a bunch of related code together: module Graphics( module Window, module Fonts, module Events, ... ) where import Window import Fonts import Events ... You can't do this if names in Window and Fonts (say) overlap because they would have to be referred to by the same prefix. An early version of my graphics library ran into this problem - I tried to use the names "create", "delete" and "select" for creation, etc. of fonts, drawing styles, colours, etc. and got a whole bunch of complaints from users. But some counterexamples exist. For example, I share names between modules like PrettyPrint and Parse which do related but different things. For example, I have: Pretty.int :: Int -> Doc -- print an int e.g., int 3 -> "3" Parse.int :: Parse Int -- parse an int Pretty.quote :: Doc -> Doc -- print argument adding quotes round it -- e.g., quote (int 3) -> "'3'" Parse.quote :: Parse a -> Parse a -- parse something with quotes round it -- e.g., (quote int) "'3'" -> 3 This emphasises the parallels between these types, makes it easier to remember the names of the functions and avoids me having to think of new names for them. In practice, very few modules import both Pretty and Parse - the ones most likely to import both seem to be Main modules. Or in a compiler I might have different sets of datatypes for code that has been parsed but not typechecked or desugared and for code that have been typechecked and desugared. Both sets of datatypes need things like expressions, declarations, etc. so it's natural to have: Abstract.Expr -- expressions in "abstract syntax" (i.e., fresh from parser) Core.Expr -- expressions in "core syntax" (after desugaring) Again, very few modules import both types. The only one in my compiler is the module which converts between these two datatypes and there it helps clarify the structure of the system to add qualifiers. (Incidentally, I import these modules using "import qualified Abstract as A" and "import qualified Core as C" to avoid being overwhelmed by clutter.) In both cases I could avoid this overlap but because I still want to emphasise relationships, I'd do that by adding a prefix so I might as well use qualified names. With these examples, I don't run into the bundling problem above because they tend not to be names I want to bundle together. Hope this helps, -- Alastair Reid reid@cs.utah.edu http://www.cs.utah.edu/~reid/
participants (2)
-
Alastair David Reid
-
Mark Carroll