Joachim Breitner | 4 Oct 11:07 2013
Picon

Module reexports at the package level

Hi,

not sure if this is the right mailing list, as it affects GHC and Cabal,
but can be used by all library authors. But it is a close fit.

I’d like to propose Module re-reports on the package level, in order to
make package reorganization easier on the users. For details, please see
http://ghc.haskell.org/trac/ghc/wiki/ModuleReexports
and for discussion, I suggest to use the trac ticket
http://ghc.haskell.org/trac/ghc/ticket/8407

Questions are:
 * Is this useful enough?
 * Is the design (syntax and semantics) good?

Thanks,
Joachim

--

-- 
Joachim “nomeata” Breitner
  mail <at> joachim-breitner.de • http://www.joachim-breitner.de/
  Jabber: nomeata <at> joachim-breitner.de  • GPG-Key: 0x4743206C
  Debian Developer: nomeata <at> debian.org
_______________________________________________
Libraries mailing list
Libraries <at> haskell.org
http://www.haskell.org/mailman/listinfo/libraries
(Continue reading)

Roman Cheplyaka | 4 Oct 12:05 2013

Re: Module reexports at the package level

* Joachim Breitner <mail <at> joachim-breitner.de> [2013-10-04 11:07:33+0200]
> Hi,
> 
> not sure if this is the right mailing list, as it affects GHC and Cabal,
> but can be used by all library authors. But it is a close fit.
> 
> I’d like to propose Module re-reports on the package level, in order to
> make package reorganization easier on the users. For details, please see
> http://ghc.haskell.org/trac/ghc/wiki/ModuleReexports
> and for discussion, I suggest to use the trac ticket
> http://ghc.haskell.org/trac/ghc/ticket/8407
> 
> Questions are:
>  * Is this useful enough?
>  * Is the design (syntax and semantics) good?

This looks useful — it could help solve the problem of fine-grained
packages, by providing a means to create meta-packages on which one can
depend. For that it would be also useful to be able to re-export whole
packages, similarly to how we can re-export modules from other modules.

I have two concerns about versioning:

1. Suppose that package-a re-exports Data.Bar from package-b starting
   from package-a-2.0 and package-b-2.0. This means that we shouldn't
   prevent packages to be built with package-a-1.0 and package-b-2.0,
   because that would result in a duplicate module Data.Bar.

   Note that we cannot simply make package-b-2.0 depend on package-a >=2.0,
   because that would result in a recursive dependency. Yet it might be
(Continue reading)

Joachim Breitner | 4 Oct 12:33 2013
Picon

Re: Module reexports at the package level

Hi,

Am Freitag, den 04.10.2013, 13:05 +0300 schrieb Roman Cheplyaka:
> I have two concerns about versioning:
> 
> 1. Suppose that package-a re-exports Data.Bar from package-b starting
>    from package-a-2.0 and package-b-2.0. This means that we shouldn't
>    prevent packages to be built with package-a-1.0 and package-b-2.0,
>    because that would result in a duplicate module Data.Bar.

you mean „should“, right?

I’m not sure if I understand your example. Does package-a-1.0 provide
Data.Bar? Are you sure that this is not covered by the PVP?

> 2. If package-b has a major API change, it would bump its version, say,
>    to 3.0. package-a still has version 2.0, but now it re-exports a
>    completely different API.

Good point. But package-a depends on package-b, and hence a major API
bump in package-b will require at least a new minor version of
packaga-a. It is then the obligation of the author of package-a to check
if the API changes affect the re-exported packages (and I hope that
eventually we’ll have tools that help with that).

Greetings,
Joachim

--

-- 
Joachim “nomeata” Breitner
(Continue reading)

Roman Cheplyaka | 4 Oct 14:43 2013

Re: Module reexports at the package level

* Joachim Breitner <mail <at> joachim-breitner.de> [2013-10-04 12:33:43+0200]
> Hi,
> 
> Am Freitag, den 04.10.2013, 13:05 +0300 schrieb Roman Cheplyaka:
> > I have two concerns about versioning:
> > 
> > 1. Suppose that package-a re-exports Data.Bar from package-b starting
> >    from package-a-2.0 and package-b-2.0. This means that we shouldn't
> >    prevent packages to be built with package-a-1.0 and package-b-2.0,
> >    because that would result in a duplicate module Data.Bar.
> 
> you mean „should“, right?

Yes, sorry.

> I’m not sure if I understand your example. Does package-a-1.0 provide
> Data.Bar? Are you sure that this is not covered by the PVP?

The problematic situation could look like this:

package-a-1.0

  provides Data.Bar

package-b-2.0

  provides Data.Bar

package-a-1.0.1

(Continue reading)

Joachim Breitner | 4 Oct 20:02 2013
Picon

Re: Module reexports at the package level

Hi,

Am Freitag, den 04.10.2013, 15:43 +0300 schrieb Roman Cheplyaka:
> The problematic situation could look like this:
> 
> package-a-1.0
> 
>   provides Data.Bar
> 
> package-b-2.0
> 
>   provides Data.Bar
> 
> package-a-1.0.1
> 
>   re-exports Data.Bar from package-b-2.0
> 
> Now, the change between package-a-1.0 and package-a-1.0.1 may seem
> almost invisible for the users, but if something depends on
> 
>   package-a ==1.0.*,
>   package-b ==2.0
> 
> ... then we have a conflict in case package-a-1.0 is picked.
> 
> But now I think this example is contrived because the constraint should
> really be package-a >= 1.0.1 && < 1.1 (we could only test our
> package successfully with package-a-1.0.1, and even ignoring module
> re-exports, package-a-1.0.1 could have added new entities).

(Continue reading)

Simon Marlow | 14 Oct 17:39 2013
Picon

Re: Module reexports at the package level

On 04/10/2013 11:07, Joachim Breitner wrote:
> not sure if this is the right mailing list, as it affects GHC and Cabal,
> but can be used by all library authors. But it is a close fit.
>
> I’d like to propose Module re-reports on the package level, in order to
> make package reorganization easier on the users. For details, please see
> http://ghc.haskell.org/trac/ghc/wiki/ModuleReexports
> and for discussion, I suggest to use the trac ticket
> http://ghc.haskell.org/trac/ghc/ticket/8407
>
> Questions are:
>   * Is this useful enough?
>   * Is the design (syntax and semantics) good?

It's not clear whether it's worth doing this, because it doesn't add any 
new functionality, only convenience.  To re-export a module from a 
package you can already write a stub module like this:

   {-# LANGUAGE PackageImports #-}
   module Data.Foo (module X) where
   import "foo" Data.Foo as X

so the convenience would be not having to write (or automatically 
generate) all these stub modules.

You could implement package re-exports by automatically generating these 
stub modules, which would require only changes in Cabal.  Or you could 
implement them directly, which would need changes in lots of places - 
when I considered doing this before, I concluded that it probably wasn't 
worth it.
(Continue reading)

Edward Kmett | 14 Oct 18:08 2013
Picon

Re: Module reexports at the package level

There is one element beyond convenience.

If you launch GHCi, and load Data.Foo, then if we follow the PackageImports path there will be two modules with the same name and the choice of where to load it from will be flagged as ambiguous, asking if you meant Data.Foo from "foo" or Data.Foo from "bar", no?

-Edward



On Mon, Oct 14, 2013 at 11:39 AM, Simon Marlow <marlowsd <at> gmail.com> wrote:
On 04/10/2013 11:07, Joachim Breitner wrote:
not sure if this is the right mailing list, as it affects GHC and Cabal,
but can be used by all library authors. But it is a close fit.

I’d like to propose Module re-reports on the package level, in order to
make package reorganization easier on the users. For details, please see
http://ghc.haskell.org/trac/ghc/wiki/ModuleReexports
and for discussion, I suggest to use the trac ticket
http://ghc.haskell.org/trac/ghc/ticket/8407

Questions are:
  * Is this useful enough?
  * Is the design (syntax and semantics) good?

It's not clear whether it's worth doing this, because it doesn't add any new functionality, only convenience.  To re-export a module from a package you can already write a stub module like this:

  {-# LANGUAGE PackageImports #-}
  module Data.Foo (module X) where
  import "foo" Data.Foo as X

so the convenience would be not having to write (or automatically generate) all these stub modules.

You could implement package re-exports by automatically generating these stub modules, which would require only changes in Cabal.  Or you could implement them directly, which would need changes in lots of places - when I considered doing this before, I concluded that it probably wasn't worth it.

Cheers,
Simon
_______________________________________________
Libraries mailing list
Libraries <at> haskell.org
http://www.haskell.org/mailman/listinfo/libraries

_______________________________________________
Libraries mailing list
Libraries <at> haskell.org
http://www.haskell.org/mailman/listinfo/libraries
Joachim Breitner | 14 Oct 19:33 2013
Picon

Re: Module reexports at the package level


Hi,
Am Montag, den 14.10.2013, 17:39 +0200 schrieb Simon Marlow:
> On 04/10/2013 11:07, Joachim Breitner wrote:
> > not sure if this is the right mailing list, as it affects GHC and Cabal,
> > but can be used by all library authors. But it is a close fit.
> >
> > I’d like to propose Module re-reports on the package level, in order to
> > make package reorganization easier on the users. For details, please see
> > http://ghc.haskell.org/trac/ghc/wiki/ModuleReexports
> > and for discussion, I suggest to use the trac ticket
> > http://ghc.haskell.org/trac/ghc/ticket/8407
> >
> > Questions are:
> >   * Is this useful enough?
> >   * Is the design (syntax and semantics) good?
> 
> It's not clear whether it's worth doing this, because it doesn't add any 
> new functionality, only convenience.  To re-export a module from a 
> package you can already write a stub module like this:
> 
>    {-# LANGUAGE PackageImports #-}
>    module Data.Foo (module X) where
>    import "foo" Data.Foo as X
> 
> so the convenience would be not having to write (or automatically 
> generate) all these stub modules.

thanks for looking at this. You are missing an important bit of
semantics in my proposal: Current, if two packages foo and bar are
visible, both of which provide Data.Foo, you cannot use "import
Data.Foo" – even if one is a re-exporting stub as you suggest. With what
I have in mind, if foo re-exports bar’s Data.Foo, such an import would
be accepted. I believe this is important, as it allows package
restructuring with less breaking existing code.

There is an alternative solution to this: Use re-exporting stub modules
(as you suggest), but make GHC more liberal when multiple modules of the
same name are important: E.g.
 * ignore one if it exports precisely the same set of names and values, or
 * if it exports a subset, or even
 * only complain if an ambiguous _name_ is used from the module, and do 
   not complain if a name is used that is exported only by one Data.Foo,
   or is exported by both, but referring to the same symbol.
These have their merits (more powerful), but can also be abused more, so
but I prefer the original, less ad-hoc and more declarative approach.

Greetings,
Joachim

--

-- 
Joachim “nomeata” Breitner
  mail <at> joachim-breitner.de • http://www.joachim-breitner.de/
  Jabber: nomeata <at> joachim-breitner.de  • GPG-Key: 0x4743206C
  Debian Developer: nomeata <at> debian.org
_______________________________________________
Libraries mailing list
Libraries <at> haskell.org
http://www.haskell.org/mailman/listinfo/libraries
Simon Marlow | 15 Oct 09:50 2013
Picon

Re: Module reexports at the package level

On 14/10/2013 19:33, Joachim Breitner wrote:

> thanks for looking at this. You are missing an important bit of
> semantics in my proposal: Current, if two packages foo and bar are
> visible, both of which provide Data.Foo, you cannot use "import
> Data.Foo" – even if one is a re-exporting stub as you suggest. With what
> I have in mind, if foo re-exports bar’s Data.Foo, such an import would
> be accepted. I believe this is important, as it allows package
> restructuring with less breaking existing code.

Yes, good point.  This wasn't an issue when we were using stubs before, 
because you would be using *either* base-3 or base-4, but not both.

> There is an alternative solution to this: Use re-exporting stub modules
> (as you suggest), but make GHC more liberal when multiple modules of the
> same name are important: E.g.
>   * ignore one if it exports precisely the same set of names and values, or
>   * if it exports a subset, or even
>   * only complain if an ambiguous _name_ is used from the module, and do
>     not complain if a name is used that is exported only by one Data.Foo,
>     or is exported by both, but referring to the same symbol.
> These have their merits (more powerful), but can also be abused more, so
> but I prefer the original, less ad-hoc and more declarative approach.

The third option sounds reasonable, as a generalisation of the way 
ambiguous identifiers are currently handled.  In fact, if we want to 
re-export only a subset of the original module, then we have to use a 
stub (rather than re-exporting at the package level), and so we end up 
needing this change to ambiguity checking.

Re-exporting a subset of another module is common.  If we're providing 
an old API in terms of a new one, each of the modules of the old API 
will re-export the subset of the new API that corresponds to the old API.

Cheers,
Simon
Joachim Breitner | 15 Oct 10:44 2013
Picon

Re: Module reexports at the package level

Hi,

Am Dienstag, den 15.10.2013, 09:50 +0200 schrieb Simon Marlow:
> > There is an alternative solution to this: Use re-exporting stub modules
> > (as you suggest), but make GHC more liberal when multiple modules of the
> > same name are important: E.g.
> >   * ignore one if it exports precisely the same set of names and values, or
> >   * if it exports a subset, or even
> >   * only complain if an ambiguous _name_ is used from the module, and do
> >     not complain if a name is used that is exported only by one Data.Foo,
> >     or is exported by both, but referring to the same symbol.
> > These have their merits (more powerful), but can also be abused more, so
> > but I prefer the original, less ad-hoc and more declarative approach.
> 
> The third option sounds reasonable, as a generalisation of the way 
> ambiguous identifiers are currently handled.  In fact, if we want to 
> re-export only a subset of the original module, then we have to use a 
> stub (rather than re-exporting at the package level), and so we end up 
> needing this change to ambiguity checking.
> 
> Re-exporting a subset of another module is common.  If we're providing 
> an old API in terms of a new one, each of the modules of the old API 
> will re-export the subset of the new API that corresponds to the old API.

you really think so? I was not bold enough to suggest that, but OTOH
many nice things can be done with it (and many non-nice).

For example, if we’d implement that, it means that packages can start to
provide a module named "Prelude" to automatically and conveniently amend
the default imports.

While it would definitely solve my itch, I’m a bit worried that it would
open the floodgates to quite messy cross-package modules.

Greetings,
Joachim

--

-- 
Joachim “nomeata” Breitner
  mail <at> joachim-breitner.de • http://www.joachim-breitner.de/
  Jabber: nomeata <at> joachim-breitner.de  • GPG-Key: 0x4743206C
  Debian Developer: nomeata <at> debian.org
_______________________________________________
Libraries mailing list
Libraries <at> haskell.org
http://www.haskell.org/mailman/listinfo/libraries

Gmane