RE: [Haskell-cafe] Packages and modules

Simon and I have been thinking about fixing this, and we think we might actually do so for GHC 6.6. Your message provoked us to write up the design. It's here http://hackage.haskell.org/trac/ghc/wiki/GhcPackages Feedback welcome It's worth reading the old threads; for example http://www.haskell.org//pipermail/libraries/2005-August/004281.html But there are many others! Simon | -----Original Message----- | From: haskell-cafe-bounces@haskell.org [mailto:haskell-cafe-bounces@haskell.org] On Behalf Of Brian | Hulley | Sent: 25 June 2006 10:16 | To: Haskell-cafe | Subject: [Haskell-cafe] Packages and modules | | Hi - | At the moment there is a problem in that two packages P and Q could contain | the same hierarchical module eg Data.Foo, and the only way for user code to | ensure the "right" Data.Foo is used is to ensure that packages P and Q are | searched in the right order. | However suppose P and Q also contain another module with the same name, eg | Data.Bar. | And suppose a user module wants to use Data.Foo from P but Data.Bar from | Q!!!

Simon Peyton-Jones wrote:
Simon and I have been thinking about fixing this, and we think we might actually do so for GHC 6.6. Your message provoked us to write up the design. It's here http://hackage.haskell.org/trac/ghc/wiki/GhcPackages Feedback welcome
It's worth reading the old threads; for example
http://www.haskell.org//pipermail/libraries/2005-August/004281.html But there are many others!
[from wiki]
ghc -c -package P1 M1.hs ghc -c -package P2 M2.hs ...compile other modules... ghc -o app M1.o M2.o ... -package P1 -package P2
I don't think this solves the whole problem. Suppose M1 needs to use A.B.C from P1 *and* A.B.C from P2, then it would need to be compiled with P1 and P2, and there is no way (from the part of the proposal in this section alone) to distinguish between these packages from within M1 itself if we're still to be limited by the import A.B.C syntax. It only seems to address the problem of app needing to use M1 and M2 but not A.B.C directly where M1 only uses P1 and M2 only uses P2. [from wiki]
import Packages.Gtk-1_3_4.Widget.Button
Allowing package aliases in the source could make this easier to type and avoid the necessity to capitalise and change underscores to dots: package gtk-1_3_4 as Gtk or package gtk as Gtk -- use the current version of gtk or if package directive is omitted an import Xyz/Mod is equivalent to: package xyz as Xyz -- initial letter capitalised import Xyz/Mod and making the package part of the module id explicit prevents ambiguity problems (David House's idea) though at the expense of using more syntax ie import Widget.Button from Gtk or import Gtk/Widget.Button -- instead of grafting In all cases I think it would be an absolute disaster to allow modules to be imported without an explicit package id because this would defeat the whole purpose of having a simple per-package namespace for modules and wouldn't allow the reader of source to know which packages it's referring to. Of course all code would need to be changed, but this could be accomplished by a conversion program which, given a list of packages and alias names, would just recursively traverse a source directory replacing imports and module exports by package directives and the fully qualified name of each module. [from wiki]
Optional extra: grafting
ambiguity ( http://www.haskell.org//pipermail/haskell-cafe/2006-June/016317.html ) The use of / instead of . (or from) gives the advantage of grafting in terms of succinct qualified module names without this ambiguity. Summary of my suggestions: 1) All module names would be of the form PackageAlias/ModId 2) package directives in the source bind aliases to actual packages 3) version number or package directive can be omitted when we are only interested in using the current version of that package 4) Package aliases have their own namespace Regards, Brian. -- Logic empowers us and Love gives us purpose. Yet still phantoms restless for eras long past, congealed in the present in unthought forms, strive mightily unseen to destroy us. http://www.metamilk.com

Brian Hulley wrote:
import Gtk/Widget.Button -- instead of grafting
In all cases I think it would be an absolute disaster to allow modules to be imported without an explicit package id because this would defeat the whole purpose of having a simple per-package namespace for modules and wouldn't allow the reader of source to know which packages it's referring to.
I meant the above only in relaiton to modules in other packages. Modules in the current package would be identified as they are at the moment, without any package qualification (since only the compiler command line would know the name of the current package). Here is an example of a module before and after applying my proposed syntax to the source of a module in some hypothetical package called duma: module Duma.Text.Line ( T , ... ) where import Prelude hiding(length, take, drop) import qualified Prelude as P import Duma.Prime.Strict import qualified Data.ByteString.Char8 as B and after: module Text.Line ( T , ... ) where import Base/Prelude hiding(length, take, drop) import qualified Base/Prelude as P import Prime.Strict import qualified Fps/Data.ByteString.Char8 as B So all that's needed is qualifying the Prelude and ByteString modules by Base/ and Fps/ respectively and we've gained the advantage of not having to decide on the name of the actual package (duma) in advance, and also not having to incorporate this name everywhere as part of the module name within the source of the duma package itself. Explicit package directives would only be needed if we wanted to refer to some specific version of a package eg package fps-0.6 as Fps but I'd imagine that usually we want to use the latest version. With the above syntax I think the only thing that has to be unique are the package names ie fps-0.6 must always refer to the one and only fast packed string package otherwise we'd end up with a nightmare of incompatibility when trying to compile other people's code. Regards, Brian. -- Logic empowers us and Love gives us purpose. Yet still phantoms restless for eras long past, congealed in the present in unthought forms, strive mightily unseen to destroy us. http://www.metamilk.com

On Mon, Jun 26, 2006 at 04:20:16PM +0100, Brian Hulley wrote:
I don't think this solves the whole problem. Suppose M1 needs to use A.B.C from P1 *and* A.B.C from P2
For a simple example of a case where this might arise, suppose M1 is the migration module for data (stored in a database, received over a network, or some other such case) in P version 1's format to P version 2's format.
[from wiki]
import Packages.Gtk-1_3_4.Widget.Button
I'm also not a fan of this magic Packages.* hierarchy, nor the package name change hoops it makes us jump through.
package gtk-1_3_4 as Gtk or package gtk as Gtk -- use the current version of gtk or if package directive is omitted an import Xyz/Mod is equivalent to:
package xyz as Xyz -- initial letter capitalised import Xyz/Mod
The "package gtk as Gtk" bit makes sense to me, but I'd expect then to use "Gtk.Foo.Bar" for module "Foo.Bar" in package "Gtk". "import gtk-1.3.4/Foo.Bar" also makes sense, although personally I'd prefer the syntax from gtk-1.3.4 import Foo.Bar where either "from <packagename>" is an optional prefix to current import declaration syntax, or "from <packagename>" starts a block so we can say from gtk1 import Foo.Bar as Gtk1.Foo.Bar import Baz.Quux as Gtk1.Baz.Quux from gtk2 import Foo.Bar as Gtk2.Foo.Bar import Baz.Quux as Gtk2.Baz.Quux If we have gtk-1.something and gtk-2.something (rather than gtk1-version and gtk2-version as above) then we'd probably instead want the wiki's -package gtk-2.0.1=Gtk2 which could be generated due to a .cabal build-depends of gtk (>= 2) as Gtk2 Thanks Ian

Simon, We covered this extensively in the Cabal vs Haskell thread starting here: http://www.haskell.org//pipermail/libraries/2005-April/003607.html You concluded it by saying on April 22: And this observation points towards a simpler solution: rather than invisibly pre-pend the package name, just get the programmer to do so. So package P exposes a module called P.M and package Q exposes Q.M. All P's internal modules are called P.something, and similarly for Q. (We rely on some social mechanism for allocating new package names, as now.) Now of course you can import P.M and Q.M in a single module. That would be simple. It might be pretty inconvenient to say 'import Base.Data.List' rather than just 'import Data.List'. But nothing forces you to do this -- and indeed we don't do it for the current 'base' package. The point is that it's an easy way for a package author to ensure their package won't conflict with others. If they choose not to avail themselves of it, it's more likely that their package will be unusable because of accidental name conflicts. Bottom line: the current story is pretty defensible. I'm not sure that keeping names unique by implicitly using package-ids is worth the bother. http://www.haskell.org//pipermail/libraries/2005-April/003672.html It seems like you are changing your position with this proposal? Any reason for doing so? -Alex- ______________________________________________________________ S. Alexander Jacobson tel:917-770-6565 http://alexjacobson.com On Mon, 26 Jun 2006, Simon Peyton-Jones wrote:
Simon and I have been thinking about fixing this, and we think we might actually do so for GHC 6.6. Your message provoked us to write up the design. It's here http://hackage.haskell.org/trac/ghc/wiki/GhcPackages Feedback welcome
It's worth reading the old threads; for example
http://www.haskell.org//pipermail/libraries/2005-August/004281.html But there are many others!
Simon
| -----Original Message----- | From: haskell-cafe-bounces@haskell.org [mailto:haskell-cafe-bounces@haskell.org] On Behalf Of Brian | Hulley | Sent: 25 June 2006 10:16 | To: Haskell-cafe | Subject: [Haskell-cafe] Packages and modules | | Hi - | At the moment there is a problem in that two packages P and Q could contain | the same hierarchical module eg Data.Foo, and the only way for user code to | ensure the "right" Data.Foo is used is to ensure that packages P and Q are | searched in the right order. | However suppose P and Q also contain another module with the same name, eg | Data.Bar. | And suppose a user module wants to use Data.Foo from P but Data.Bar from | Q!!! _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

I'm not sure on which mail of this thread I should append MHO. What happens if two programmers "happen" to choose the same package name? (Prepend the location on the filesystem? ;-) If something like a package name is introduced I would prefer not separating package and module name with a "." because you might then even use the package name to point to a web address from where to load code (source/ binary/ byte code??) from.. Then creating something like Java applets would be more easy. We can't ignore this completely as the world (or important parts eg Windows) will try to bring more richness to internet applications/ the user.. They strive to integrate web applications so that you as user can't see if you're running a native or a downloaded application... If you use eg "," as separator you can use dots in the package name without hassle. Marc

Marc Weber wrote:
I'm not sure on which mail of this thread I should append MHO.
What happens if two programmers "happen" to choose the same package name? (Prepend the location on the filesystem? ;-)
If something like a package name is introduced I would prefer not separating package and module name with a "." because you might then even use the package name to point to a web address from where to load code (source/ binary/ byte code??) from.. Then creating something like Java applets would be more easy. We can't ignore this completely as the world (or important parts eg Windows) will try to bring more richness to internet applications/ the user.. They strive to integrate web applications so that you as user can't see if you're running a native or a downloaded application... If you use eg "," as separator you can use dots in the package name without hassle.
I think the package alias syntax would help here eg (non-existent url): package http://www.metamilk.com/packages/duma-1.0 as Duma import Duma/Text.Line -- etc I don't think the package name should ever be written directly into the import statement, because the package name needs to be able to use normal filename syntax but a component of a module identifier needs to conform to Haskell syntax because it could be used anywhere (*) eg let x = Duma/Text.Line.take 5 y Also, to clarify my reasons for wanting to make the package part of the module id syntactically distinct (by using eg / instead of .), the entire namespace of hierarchical modules is supposed to be internal to each package, and therefore any id of the form A.B.C belongs to this internal namespace and therefore must refer to an internal module. All modules in external packages have ids of the form PackageAlias/ModulePath so when you read the source you (and the compiler) can tell at a glance whether you're referring to an internal or external module. An extra advantage of making the package alias part syntactically visible is that we could make package directives optional in the common case where we want to just use the latest version of a package that has a globally agreed name eg import Fps/Data.ByteString -- uses latest fps package whereas if we just used import Fps.Data.ByteString the compiler would have no way to tell whether we're referring to an external package Fps or another module in our own package, and, imho, this would just simply be messy and inconsistent. Also, although this requires changes to existing code, it should be possible to completely automate the change by using a simple conversion utility which knows about current packages, their prefixes, and what modules they contain (and therefore should be much less troublesome than the change from flat module namespace to hierarchical namespace). (*) As an aside, it is a question to me whether identifiers in the body of a module should be allowed to be qualified with anything other than a module *alias*. Haskell98 just had flat modules, so the qualification was of the form A.val, whereas with the hierarchical extension you can use A.B.C.val etc. However does anyone actually ever use this rather than specifying an alias for A.B.C and using the alias to qualify val instead? This becomes a more urgent question if the lexical syntax for a module id needs to use another symbol such as /. Regards, Brian. -- Logic empowers us and Love gives us purpose. Yet still phantoms restless for eras long past, congealed in the present in unthought forms, strive mightily unseen to destroy us. http://www.metamilk.com

Concerning packages, Alex asks: | We covered this extensively in the Cabal vs Haskell thread starting | here: http://www.haskell.org//pipermail/libraries/2005-April/003607.html | | You concluded it by saying on April 22: | | And this observation points towards a simpler solution: rather than | invisibly pre-pend the package name, just get the programmer to do so. | So package P exposes a module called P.M and package Q exposes Q.M. All | P's internal modules are called P.something, and similarly for Q. (We | rely on some social mechanism for allocating new package names, as now.) | Now of course you can import P.M and Q.M in a single module. | | That would be simple. It might be pretty inconvenient to say 'import | Base.Data.List' rather than just 'import Data.List'. But nothing forces | you to do this -- and indeed we don't do it for the current 'base' | package. The point is that it's an easy way for a package author to | ensure their package won't conflict with others. If they choose not to | avail themselves of it, it's more likely that their package will be | unusable because of accidental name conflicts. | | Bottom line: the current story is pretty defensible. I'm not sure that | keeping names unique by implicitly using package-ids is worth the | bother. | | http://www.haskell.org//pipermail/libraries/2005-April/003672.html | | It seems like you are changing your position with this proposal? Any | reason for doing so? A fair question. The basic reason is that packages are now a "given". Cabal has packages, with globally unique names and versioning, and we should build on, not duplicate, this infrastructure. Once someone establishes a unique package name, that should be enough: no need to *additionally* establish unique module names, let alone for every single module in the package. Concerning other mail on this subject, which has been v useful, I've revised the Wiki page (substantially) to take it into account. http://hackage.haskell.org/trac/ghc/wiki/GhcPackages Further input (either by email or by adding material to the Wiki) would be welcome. (No guarantee Simon M agrees with what I've written... I'm at home this afternoon :-) Simon

Simon Peyton-Jones wrote:
Concerning other mail on this subject, which has been v useful, I've revised the Wiki page (substantially) to take it into account. http://hackage.haskell.org/trac/ghc/wiki/GhcPackages
Further input (either by email or by adding material to the Wiki) would be welcome. (No guarantee Simon M agrees with what I've written... I'm at home this afternoon :-)
I think the following is a non-question: An open question: if A.B.C is in the package being compiled, and in an exposed package, and you say import A.B.C, do you get an error ("ambiguous import"), or does the current package override. because if the suggested syntax is used, import directives come in two flavours: ones that use "from" to import from a different package and ones that don't use "from" and therefore must refer to the current package. There would be no such thing as an "exposed" package (afaiu the idea of "exposure" is only needed in the context of different packages needing to share the same module namespace, which the proposal will hopefully make a thing of the past). Here are some other points: 1) What is the meaning of A.B.C.id ? I think this would have to refer to id in the module A.B.C in the package being compiled. To refer to an id in some other package, you'd have to use an alias eg import qualified A.B.C from "base" as P P.id -- P refers to the aliased module (Aliases hide modules in the current package with the same modid when that modid is used to qualify something) To avoid the need to use aliases here, a different syntax eg Base/A.B.C.id would need to be used (where Base is a package alias for "base") but it seems unlikely that anyone would find a reason to not want to use an alias in such cases so this other syntax wouldn't be necessary. 2) Exporting modules from other packages. (This also relates to the Haskell' proposal for qualified exports at http://hackage.haskell.org/trac/haskell-prime/wiki/ModuleSystem#Permitqualif... ) 2a) Exporting the contents of an external module module Foo ( module P ) where import qualified A.B.C from "extpkg" as P 2b) Exporting the contents of an external module qualified module Foo ( qualified module P ) where import qualified A.B.C from "extpkg" as P In both cases an alias would be needed so we can refer to the external module in the export list without having to repeat the 'from "extpkg"' here as well. And since we are using aliases, it makes sense to modify the poposed H' syntax to allow qualified module M to be short for: qualified module M as M where M is either an alias or a module in the current package. 3) Syntax: I liked Ian Lynagh's suggestion of using "from" to start either a single import directive or a block of import directives http://www.haskell.org//pipermail/haskell-cafe/2006-June/016338.html eg (modified to use quotes): from "base" import Predude hiding(length) import Control.Exception import qualified Data.List as List since otherwise it would soon become a bit of a pain to have to type 'from "base"' everywhere (esp if the package name was some long URL). It would also make it easier to quickly change to a different package without having to modify multiple import directives, which might be especially useful in the context of using a debug or release version of a package by putting C pre-processor directives around the "from" part. There is a minor open question about the exact indentation rule for the above syntax since "base" is not a keyword and it would seem strange to desugar it into from {"base"; import ... } so it looks like it would need a special layout rule that would give a desugaring into from "base" {import ...} Regards, Brian. -- Logic empowers us and Love gives us purpose. Yet still phantoms restless for eras long past, congealed in the present in unthought forms, strive mightily unseen to destroy us. http://www.metamilk.com

Brian Hulley wrote:
Simon Peyton-Jones wrote:
I think the following is a non-question:
An open question: if A.B.C is in the package being compiled, and in an exposed package, and you say import A.B.C, do you get an error ("ambiguous import"), or does the current package override.
because if the suggested syntax is used, import directives come in two flavours: ones that use "from" to import from a different package and ones that don't use "from" and therefore must refer to the current package. There would be no such thing as an "exposed" package (afaiu the idea of "exposure" is only needed in the context of different packages needing to share the same module namespace, which the proposal will hopefully make a thing of the past).
I wonder if the wiki question refers to issues of backwards compatibility with the existing module system? Ie do you want to keep the existing module system with (all exposed) packages sharing the same module space at the same time as having a new module system with per-package namespaces? To allow both to exist simultaneously, I suggest a new keyword (and improved syntax below) to mark a per-package namespace import so that existing code using "import A.B.C" would still refer to the existing overlapped namespaces so that there wouldn't be any problems with backwards compatibility (except for the introduction of a new keyword) eg: use "base" Prelude hiding(length) qualified Data.List as List use A.B.C -- from current package import P.Q.R -- deprecated old-style import from current + exposed packages With this new syntax, my answer to the wiki question would be that the compiler should respond to "import A.B.C" where A.B.C is in an exposed package exactly as it does at the moment, whatever way that is, since people can always choose to resolve the ambiguity properly using the new syntax. Regards, Brian. -- Logic empowers us and Love gives us purpose. Yet still phantoms restless for eras long past, congealed in the present in unthought forms, strive mightily unseen to destroy us. http://www.metamilk.com

On Wed, Jul 05, 2006 at 01:03:01AM +0100, Brian Hulley wrote:
Simon Peyton-Jones wrote:
Concerning other mail on this subject, which has been v useful, I've revised the Wiki page (substantially) to take it into account. http://hackage.haskell.org/trac/ghc/wiki/GhcPackages
Further input (either by email or by adding material to the Wiki) would be welcome. (No guarantee Simon M agrees with what I've written... I'm at home this afternoon :-)
I think the following is a non-question:
An open question: if A.B.C is in the package being compiled, and in an exposed package, and you say import A.B.C, do you get an error ("ambiguous import"), or does the current package override.
because if the suggested syntax is used, import directives come in two flavours: ones that use "from" to import from a different package and ones that don't use "from" and therefore must refer to the current package.
FWIW this isn't what I actually intended when I was talking about using "from". I was imagining it would work similar to how "foo" unqualified can refer to either an imported variable or a variable in the current package, but we can still qualify "Foo.foo" should we wish to be explicit. So you can "import" from any package, including the current one, but qualify "from package import" should you wish to be explicit.
(modified to use quotes):
from "base"
I think I missed where the plan to use quotes came from. What's the purpose? Package names already have a well-defined syntax with no spaces or other confusing characters in them, so why do we need the quotes? Or is it just so we can have packages with the same name as keywords? (if so I think personally I'd prefer a slightly more context-sensitive grammar, not entirely unlike the as/qualified/hiding semi-keywords in import statements).
import Predude hiding(length) import Control.Exception import qualified Data.List as List
since otherwise it would soon become a bit of a pain to have to type 'from "base"' everywhere (esp if the package name was some long URL). It would also make it easier to quickly change to a different package without having to modify multiple import directives, which might be especially useful in the context of using a debug or release version of a package by putting C pre-processor directives around the "from" part.
There is a minor open question about the exact indentation rule for the above syntax since "base" is not a keyword and it would seem strange to desugar it into from {"base"; import ... } so it looks like it would need a special layout rule that would give a desugaring into from "base" {import ...}
It would only be slightly different to the current rules (it would be if the second lexeme after "from" was not '{', rather than the first), although now you mention it this would be an alternative possibility: from "base" import Prelude hiding (length) Control.Exception qualified Data.List as List where "import" behaves much like "of" as far as the layout rule is concerned. Thanks Ian

Ian Lynagh wrote:
I think I missed where the plan to use quotes came from. What's the purpose? Package names already have a well-defined syntax with no spaces or other confusing characters in them, so why do we need the quotes? Or is it just so we can have packages with the same name as keywords?
I think it's non-trivial to embed the syntax of package names into the Haskell grammar. The version part will sometimes lex as a floating point literal, for example. Ugh. Strings are much easier. Cheers, Simon

Package names should never appear in source files IMHO. if a package name is in the source file, then you might as well make it part of the module name. packages exist for 'meta-organization' of code. A way to deal with mapping code _outside_ of the language itself, putting packages inside the code will force the creation of yet another level, meta-packages, or something. packages should not be a language issue, they are an environment one. John -- John Meacham - ⑆repetae.net⑆john⑈

John Meacham wrote:
Package names should never appear in source files IMHO. if a package name is in the source file, then you might as well make it part of the module name. packages exist for 'meta-organization' of code. A way to deal with mapping code _outside_ of the language itself, putting packages inside the code will force the creation of yet another level, meta-packages, or something. packages should not be a language issue, they are an environment one.
Indeed, that's the principle we've been following with the package design up until now. There are (were) two principles: 1. packages should stay out of the language 2. module names should reflect functionality *only* Sticking to these principles rigidly has left us with a problem, namely that packages lack proper abstraction properties. A hidden module in a package is visible externally, because all packages share the module namespace. So how do we fix that? a. we could put package names in module names as you suggest. But apart from sacrificing the second principle, this doesn't let you import a module from a package without specifying the exact version of the package ==> BAD. b. we could add compiler options that let you graft the module namespace of a package into the global module namespace at an arbitrary location. c. instead of grafting, we add language support to allow importing modules from a particular package (crucically, you don't have to specify the version). We were thinking about (b), when people started suggesting (c). Although (c) breaks the first principle, in many ways it's rather nicer than (b). I don't think (a) is a goer at all. So that's where we are now, if you have a better idea then let's hear it! Cheers, Simon

On 2006-07-06, Simon Marlow
a. we could put package names in module names as you suggest. But apart from sacrificing the second principle, this doesn't let you import a module from a package without specifying the exact version of the package ==> BAD.
Right. There are occasions of course that I do want to specify exact versions -- such as testing two versions side by side.
b. we could add compiler options that let you graft the module namespace of a package into the global module namespace at an arbitrary location.
This seems quite workable.
c. instead of grafting, we add language support to allow importing modules from a particular package (crucically, you don't have to specify the version).
The package still needs to be located somehow, and I don't like this split between tools and language. -- Aaron Denney -><-

"Brian Hulley"
because if the suggested syntax is used, import directives come in two flavours: ones that use "from" to import from a different package and ones that don't use "from" and therefore must refer to the current package.
What is the "current package"? My impression was that "from" would only be needed when there was ambiguity. (And if I wanted to type myself to death, I'd be using Java :-) If you *have* to specify package, this makes things a lot less flexible (e.g., moving a module from one package to another will break code) Would 'base' be the current package in most cases? That would encourage cramming even more stuff into base¹, and I suspect the overloaded 'base' is half the reason we're discussing all this extra syntactical baggage. (E.g. experimenting with a newer version of Don's FPS, I basically need to replace 'base'. With the features being discussed, I could get by rewriting the import statements in all my fps-using code, which would be an improvement. It'd be much safer and better to have a compiler option, of course, but I guess that will only work for complete packages.) Anyway (and like you say) I think the workaround using qualification or hiding is more than sufficient, I consider recycling names from imported modules for local variables questionable as best, and would rather it wasn't encouraged.
3) Syntax: I liked Ian Lynagh's suggestion of using "from" to start either a single import directive or a block of import directives http://www.haskell.org//pipermail/haskell-cafe/2006-June/016338.html eg (modified to use quotes):
from "base" import Predude hiding(length) import Control.Exception import qualified Data.List as List
Would this make 'from' a reserved word? I think this is only useful if you require the module to be declared, and thus not worth an extra keyword (and code breakage) if non-ambigous modules can still be imported. Anyway, I'd just like to say that I'm really happy about the way GHC and Cabal currently works - 'ghc --make' takes care of package imports, and Cabal is simple enough that most of my code gets Cabalized these days. -k ¹ What *is* the advantage of stuffing everything and the kitchen sink into base, btw? -- If I haven't seen further, it is by standing in the footprints of giants

Ketil Malde wrote:
What is the "current package"?
The package that you're currently compiling. This now must be known at compile time.
My impression was that "from" would only be needed when there was ambiguity. (And if I wanted to type myself to death, I'd be using Java :-) If you *have* to specify package, this makes things a lot less flexible (e.g., moving a module from one package to another will break code)
Our current plan is a relatively small delta from the current scheme: as you say, "from" is only required when there is an ambiguity. This assumes we keep the current idea of exposed/hidden packages. Having a default set of exposed packages is terribly convenient when just firing up GHCi, for example. In fact, we can imagine three states that a package could be in: - exposed: the package's modules populate the global module namespace, explicit "from" imports may be used to resolve ambiguity - hidden: the package cannot be used at all - available: the package can be used only by an explicit "from" import (this is rather like a qualified import at the package level, and might be useful if you want to use a package with module names that overlap with local modules). Currently, packages have a default state of either exposed or hidden. Cabal ignores the default state, and requires you to say explicitly which packages you want to be exposed. We don't have the "available" state, at the moment. So here are some options: 1. the proposal as it is now, keeping exposed/hidden state in the package database, don't support "available" 2. Add support for "available". Cons: yet more complexity! 3. Drop the notion of exposed/hidden, all packages are "available". (except for base?). Cons: lots more typing, very non-backwards-compatible, still have to list dependencies in .cabal files. anyone have any more suggestions? Is there any way to simplify? I rather feel this design is getting a little unwieldy. I resist the temptation to discuss syntax too early... Cheers, Simon

So here are some options:
1. the proposal as it is now, keeping exposed/hidden state in the package database, don't support "available"
2. Add support for "available". Cons: yet more complexity!
3. Drop the notion of exposed/hidden, all packages are "available". (except for base?). Cons: lots more typing, very non-backwards-compatible, still have to list dependencies in .cabal files.
anyone have any more suggestions? Is there any way to simplify? I rather feel this design is getting a little unwieldy.
Maybe a dumb question, but why not support only exposed and available? Why have hidden modules that cannot be used, even when the programmer explicitly asks for them? /Niklas

Niklas Broberg wrote:
So here are some options:
1. the proposal as it is now, keeping exposed/hidden state in the package database, don't support "available"
2. Add support for "available". Cons: yet more complexity!
3. Drop the notion of exposed/hidden, all packages are "available". (except for base?). Cons: lots more typing, very non-backwards-compatible, still have to list dependencies in .cabal files.
anyone have any more suggestions? Is there any way to simplify? I rather feel this design is getting a little unwieldy.
Maybe a dumb question, but why not support only exposed and available? Why have hidden modules that cannot be used, even when the programmer explicitly asks for them?
The main reason for wanting hidden is so that we can be sure that the build-depends field of a Cabal package is exhaustive; we currently do this by making all packages not listed in build-depends hidden. Outside of Cabal, I don't see a reason for wanting hidden. Cheers, Simon

In response to Brian and Ian's helpful comments, I've added a bunch more stuff to our proposal about packages. If I have missed anything, let me know. http://hackage.haskell.org/trac/ghc/wiki/GhcPackages If you or anyone else thinks the choices made there are poor ones, continue to say so. It's a helpful process. One particular point: | 2b) Exporting the contents of an external module qualified | | module Foo | ( qualified module P | ) where While this might be a good idea, it's an orthogonal one, and the proposal doesn't tackle it. One thing at a time! Simon

Simon Peyton-Jones wrote:
In response to Brian and Ian's helpful comments, I've added a bunch more stuff to our proposal about packages. If I have missed anything, let me know.
http://hackage.haskell.org/trac/ghc/wiki/GhcPackages
If you or anyone else thinks the choices made there are poor ones, continue to say so. It's a helpful process.
I think the proposed system is too complicated. I'd have thought there were some simple aims: 1) Backwards compatibility so existing code doesn't break 2) Allow people to use per-package module namespaces in new code 3) Allow package names to be URLs (Marc Weber's idea http://www.haskell.org//pipermail/haskell-cafe/2006-June/016378.html ) And the following possible solutions: 1) The current "import" syntax would refer to shared namespace imports (exactly as at present) 2) A new keyword, "use", would indicate use of per-package namespaces 3) Putting the package name in quotes allows more complex package names including URLs and packages located in a specific folder etc in future, and also makes it clear that the package name is an OS filename (albeit conforming to a special form) not a Haskell id, and also allows the "use" syntax to be very concise since a quoted name cannot be confused with a modid. So instead of just taking this simple solution, the wiki proposal is instead destroying the beauty of the per-package namespace idea by incorporating into it the existing shared namespaces with their attendant problems, instead of just letting the existing messy system die a natural death through the syntactic isolation I proposed. In three years' time, how easy will it be to explain Haskell's module system to a new programmer? Regards, Brian. -- Logic empowers us and Love gives us purpose. Yet still phantoms restless for eras long past, congealed in the present in unthought forms, strive mightily unseen to destroy us. http://www.metamilk.com

| So instead of just taking this simple solution, the wiki proposal is instead | destroying the beauty of the per-package namespace idea by incorporating | into it the existing shared namespaces with their attendant problems, | instead of just letting the existing messy system die a natural death | through the syntactic isolation I proposed. Brian, I think your proposal may be clearer to you than to everyone else. It's always hard to reconstruct a detailed proposal by reading long email threads. Suggestion: if you feel strongly about this, why not start a Wiki page (you can link to it from the current one) to describe the design you propose, at a comparable level of detail? Incidentally, compatibility with Cabal is a significant goal. Simon

Simon Peyton-Jones wrote:
So instead of just taking this simple solution, the wiki proposal is instead destroying the beauty of the per-package namespace idea by incorporating into it the existing shared namespaces with their attendant problems, instead of just letting the existing messy system die a natural death through the syntactic isolation I proposed.
Brian,
I think your proposal may be clearer to you than to everyone else. It's always hard to reconstruct a detailed proposal by reading long email threads.
Suggestion: if you feel strongly about this, why not start a Wiki page (you can link to it from the current one) to describe the design you propose, at a comparable level of detail?
Incidentally, compatibility with Cabal is a significant goal.
Hi Simon - Actually re-reading my post I realised I may have sounded a bit negative about the hard work you'd done to collate the various responses to form the wiki proposal - my apologies. I've followed your suggestion and made a separate page at http://hackage.haskell.org/trac/ghc/wiki/GhcPackagesAlternativeProposal (linked from the bottom of the existing page)which will hopefully make my ideas a lot clearer. I've also changed my proposed syntax so that it is 100% backwards compatible (no new keywords) with the existing module system and language (and existing package naming rules). Regards, Brian. -- Logic empowers us and Love gives us purpose. Yet still phantoms restless for eras long past, congealed in the present in unthought forms, strive mightily unseen to destroy us. http://www.metamilk.com

Brian | Actually re-reading my post I realised I may have sounded a bit negative | about the hard work you'd done to collate the various responses to form the | wiki proposal - my apologies Thanks -- email is a fragile medium! | I've followed your suggestion and made a separate page at | http://hackage.haskell.org/trac/ghc/wiki/GhcPackagesAlternativeProposal Jolly good, thank you. I've looked at it. Happily, so far as I can see the two proposals are identical! At least I cannot identify any points of difference. If you think they differ, can you say where? Your spec is a little unclear about whether the package name is compulsory in every import. Under "The best of both worlds / Shared name space" you say that plain "import A.B.C" looks in all exposed packages and bleats if its ambiguous. That's what we propose, and it's satisfactorily backward compatible. And that is what your syntax implies too. Simon

Simon Peyton-Jones wrote:
Brian
Actually re-reading my post I realised I may have sounded a bit negative about the hard work you'd done to collate the various responses to form the wiki proposal - my apologies
Thanks -- email is a fragile medium!
I've followed your suggestion and made a separate page at
http://hackage.haskell.org/trac/ghc/wiki/GhcPackagesAlternativeProposal
Jolly good, thank you. I've looked at it.
Happily, so far as I can see the two proposals are identical! At least I cannot identify any points of difference. If you think they differ, can you say where?
They are more similar than I realised at first. However there are some minor issues: 1) Qualified names: import A.B.C( T1 ) from "foo" import A.B.C( T2 ) from "bar" type S = A.B.C.T1 -> A.B.C.T2 I'd suggest that the above should give a compiler error that A.B.C is ambiguous (as a qualifier), rather than allowing T1 to disambiguate it, because otherwise it allows people to write code that could be very hard to understand ie within the code, every occurrence of A.B.C as a qualifier should refer to the same module. (Otherwise the thing qualified qualifies the qualifier that's qualifying it...) 2) Syntax I think it's important that it's as easy to use per-package namespaces as the existing shared namespace, and so my syntax doesn't require the use of an extra keyword (ie "from"), and this works syntactically because package names are string literals. (I see the original proposal has now changed to advocate that package names should indeed be quoted.)
Your spec is a little unclear about whether the package name is compulsory in every import. Under "The best of both worlds / Shared name space" you say that plain "import A.B.C" looks in all exposed packages and bleats if its ambiguous. That's what we propose, and it's satisfactorily backward compatible. And that is what your syntax implies too.
In my spec, if you omit the package name you get an "old-style" import using the shared namespace, and if you supply a package name you get a "new-style" import that only searches in the specified package: import A.B.C -- search home + exposed as is done at the moment import "" A.B.C -- search home package only import "pkg" A.B.C -- search "pkg" only So the first variant gives backwards compatibility and the other two variants give the new per-package namespaces. So apart from using "" to answer the question about importing from the home package, minimalist syntax, and the minor issue about qualification, both proposals are indeed now identical, which is great! :-) Regards, Brian. -- Logic empowers us and Love gives us purpose. Yet still phantoms restless for eras long past, congealed in the present in unthought forms, strive mightily unseen to destroy us. http://www.metamilk.com

| 1) Qualified names: | | import A.B.C( T1 ) from "foo" | import A.B.C( T2 ) from "bar" | type S = A.B.C.T1 -> A.B.C.T2 | | I'd suggest that the above should give a compiler error that A.B.C is | ambiguous (as a qualifier), rather than allowing T1 to disambiguate it, | because otherwise it allows people to write code that could be very hard to | understand ie within the code, every occurrence of A.B.C as a qualifier | should refer to the same module. (Otherwise the thing qualified qualifies | the qualifier that's qualifying it...) But that's inconsistent with Haskell 98. In H98 you can say import M( T1 ) as Q import N( T2 ) as Q type S = Q.T1 -> Q.T2 and it'll work just fine. You may think it should not work, but that's water under the bridge. We should be consistent here. | In my spec, if you omit the package name you get an "old-style" import using | the shared namespace, and if you supply a package name you get a "new-style" | import that only searches in the specified package: | | import A.B.C -- search home + exposed as is done at the moment | import "" A.B.C -- search home package only | import "pkg" A.B.C -- search "pkg" only That's exactly what our spec says too. (Good news, again.) Only maybe not explicitly enough! See the section "Is the from<package> compulsory". Perhaps you could improve the wording to make it more unambiguous? Indeed, if we've converged, would you like to fold into our draft whatever you think is useful from yours? Simon

Simon Peyton-Jones wrote:
1) Qualified names:
import A.B.C( T1 ) from "foo" import A.B.C( T2 ) from "bar" type S = A.B.C.T1 -> A.B.C.T2
I'd suggest that the above should give a compiler error that A.B.C is ambiguous (as a qualifier), rather than allowing T1 to disambiguate it, because otherwise it allows people to write code that could be very hard to understand ie within the code, every occurrence of A.B.C as a qualifier should refer to the same module. (Otherwise the thing qualified qualifies the qualifier that's qualifying it...)
But that's inconsistent with Haskell 98. In H98 you can say import M( T1 ) as Q import N( T2 ) as Q type S = Q.T1 -> Q.T2 and it'll work just fine. You may think it should not work, but that's water under the bridge. We should be consistent here.
But Q is an alias not a concrete module name like A.B.C so this is not quite the same thing imho. Q could be regarded as a new local module which contains T1 from M and T2 from N, so Q.T1 and Q.T2 both use the "same" Q. However to allow A.B.C.T1 and A.B.C.T2 is to assert that A.B.C is somehow semantically the "same" entity in both cases even though it is just pure happenstance that these modules have the same name in their respective packages. Still I can see it may be useful to regard A.B.C now as a kind of alias as well and within that view consistency with H98 is obviously important. So I think we are free to make a choice about this, but personally I don't know which one is "best".
In my spec, if you omit the package name you get an "old-style" import using the shared namespace, and if you supply a package name you get a "new-style" import that only searches in the specified package:
import A.B.C -- search home + exposed as is done at the moment import "" A.B.C -- search home package only import "pkg" A.B.C -- search "pkg" only
That's exactly what our spec says too. (Good news, again.) Only maybe not explicitly enough! See the section "Is the from<package> compulsory". Perhaps you could improve the wording to make it more unambiguous?
I think it's now explicit enough in the latest version of the wiki - I must have replied to your email before re-reading this section. The only comment I'd make is that "this" or "home" encroaches on the package namespace so I'd prefer "" or a keyword or perhaps a choice of either "" or a keyword just as we can use otherwise in place of True in the guard syntax.
Indeed, if we've converged, would you like to fold into our draft whatever you think is useful from yours?
Apart from the meaning of A.B.C.id which I don't have a strong view about (since I always use aliases anyway) but which other people may also want to comment on, both proposals have converged modulo syntax. Therefore it seems best to just leave them as they are unless you want to use my suggested syntax instead. Regards, Brian. -- Logic empowers us and Love gives us purpose. Yet still phantoms restless for eras long past, congealed in the present in unthought forms, strive mightily unseen to destroy us. http://www.metamilk.com

Brian Hulley wrote:
Simon Peyton-Jones wrote:
compulsory". Perhaps you could improve the wording to make it more unambiguous?
Indeed, if we've converged, would you like to fold into our draft whatever you think is useful from yours?
[snip]
Therefore it seems best to just leave them as they are unless you want to use my suggested syntax instead.
I've added the point about "from" being redundant to the syntax section and made a new section to summarise the resulting concrete syntax that is derived conversationally in the previous section, which might also help to clarify the meaning of the different variants of import directive. Please feel free to delete it if you think this is too concrete at this stage for this draft. Regards, Brian. -- Logic empowers us and Love gives us purpose. Yet still phantoms restless for eras long past, congealed in the present in unthought forms, strive mightily unseen to destroy us. http://www.metamilk.com

"Simon Peyton-Jones"
Brian Hulley wrote:
| import A.B.C( T1 ) from "foo" | import A.B.C( T2 ) from "bar" | type S = A.B.C.T1 -> A.B.C.T2
| I'd suggest that the above should give a compiler error that A.B.C is | ambiguous (as a qualifier), rather than allowing T1 to disambiguate it,
But that's inconsistent with Haskell 98.
FWIW, I agree with Brian that this is not good practice. If it can't be forbidden, I would suggest that compilers emit a warning about it. -k -- If I haven't seen further, it is by standing in the footprints of giants

"Simon Peyton-Jones"
writes: Brian Hulley wrote:
| import A.B.C( T1 ) from "foo" | import A.B.C( T2 ) from "bar" | type S = A.B.C.T1 -> A.B.C.T2
| I'd suggest that the above should give a compiler error that A.B.C is | ambiguous (as a qualifier), rather than allowing T1 to disambiguate it,
But that's inconsistent with Haskell 98.
FWIW, I agree with Brian that this is not good practice. If it can't be forbidden, I would suggest that compilers emit a warning about it.
Is there really a case where someone would use that pattern intentionally? I'd vote for making it an error by default. Perhaps then a flag would be available that says "accept dangerous constructs that are legal according to Haskell 98".
-k -- If I haven't seen further, it is by standing in the footprints of giants
_______________________________________________ Glasgow-haskell-users mailing list Glasgow-haskell-users@haskell.org http://www.haskell.org/mailman/listinfo/glasgow-haskell-users

seth@cql.com wrote:
"Simon Peyton-Jones"
writes: Brian Hulley wrote: | import A.B.C( T1 ) from "foo" | import A.B.C( T2 ) from "bar" | type S = A.B.C.T1 -> A.B.C.T2 | I'd suggest that the above should give a compiler error that A.B.C is | ambiguous (as a qualifier), rather than allowing T1 to disambiguate it, But that's inconsistent with Haskell 98. FWIW, I agree with Brian that this is not good practice. If it can't be forbidden, I would suggest that compilers emit a warning about it.
Is there really a case where someone would use that pattern intentionally? I'd vote for making it an error by default. Perhaps then a flag would be available that says "accept dangerous constructs that are legal according to Haskell 98".
The Haskell 98 behavior compensates for the case where the module you used to import Old (foo,bar) has been split into two new modules, A(foo) and B(bar). You can import A as Old and B as Old so that Old.foo and Old.bar now resolve to A.foo and B.bar. I expect the pattern for the above would actually be closer to
import Old(T1,T2) from "original"
mine :: Old.T1 -> Old.T2
becoming
import qualified A.B.C(T1) as Old from "foo" import qualified D.E.F(T2) as Old from "bar"
mine :: Old.T1 -> Old.T2
Which is a syntax that should be supported. -- Chris
participants (12)
-
Aaron Denney
-
Brian Hulley
-
Chris Kuklewicz
-
Ian Lynagh
-
John Meacham
-
Ketil Malde
-
Marc Weber
-
Niklas Broberg
-
S. Alexander Jacobson
-
seth@cql.com
-
Simon Marlow
-
Simon Peyton-Jones