
(sorry, I responded to the wrong list)
On 10/24/06, Duncan Coutts
On the other hand, in Gtk2Hs I know one case where we do this. We have a Graphics.UI.Gtk.Cairo api module that is only included if Gtk was built against Cairo. In any case it could be faked by using cpp to just not export anything rather than not having the module exposed at all. So it's not clear that it's worth banning. Or maybe making it slightly harder is worth it so that people don't get in the habit.
Couldn't you split this into Gtk and Gtk-Cairo packages, where the latter is only built if Cairo is available? Similarly, in your GUI example, couldn't you have seperate foo and foo-gui packages, and only build the foo-gui package if the GUI libraries are available? Otherwise, how can you say "I depend on the Gtk package being built with Cairo support" and "I depend on the GUI portion of the foo package?" In general, optional groups of modules should be split off into separate packages, and there should be a way of building a bundle of related packages together (just like one can build a group of related executables together already). Regards, Brian

On 24.10 21:45, Brian Smith wrote:
Couldn't you split this into Gtk and Gtk-Cairo packages, where the latter is only built if Cairo is available? Similarly, in your GUI example, couldn't you have seperate foo and foo-gui packages, and only build the foo-gui package if the GUI libraries are available?
Otherwise, how can you say "I depend on the Gtk package being built with Cairo support" and "I depend on the GUI portion of the foo package?"
In general, optional groups of modules should be split off into separate packages, and there should be a way of building a bundle of related packages together (just like one can build a group of related executables together already).
The problem is that this creates a very large number of packages which may have recursive dependencies (not supported by GHC!). Also in many cases this would result in 1 package -> 10 packages most of which with one module. - Einar Karttunen

On 10/25/06, Einar Karttunen
In general, optional groups of modules should be split off into separate packages, and there should be a way of building a bundle of related
On 24.10 21:45, Brian Smith wrote: packages
together (just like one can build a group of related executables together already).
The problem is that this creates a very large number of packages which may have recursive dependencies (not supported by GHC!).
Also in many cases this would result in 1 package -> 10 packages most of which with one module.
Please point out some cases where splitting a package into multiple packages would lead to recursive package dependencies so I can study them. I understand that this would increase the number of packages. But, if it would increase the number of packages 10x, then that means that the original package could be configured with 10 different subsets of functionality. In that case, saying "Build-depends: foo" for that package foo would be almost meaningless. You would need to add some kind of more specific dependency like "Build-depends: foo (Foo.Bar.A, Foo.Bar.C, Foo.Bar.D)" to indicate what modules you need from foo. Packages should be created in such a way that the set of things exported from the package should not change based on configuration. If some features are only valid under one configuration, then they should be factored out into a seperate module and then a seperate package. For example, GHC-specific features should be factored out into a separate package, Windows-specific features should be factored out into a separate package, etc. More-or-less, that is how the hierarchical libraries are designed at the module level. If you have that, then the Build-depends field is very useful. Build-depends: foo, foo-ghc, foo-windows Here, it is clear that the package will only work on GHC on Windows. "build configure" will tell you what is wrong. If all of these packages remained together as one package, you would have: Build-depends: foo The GHC or Windows requirement is not obvious. "build configure" will not give you any indication that something is wrong. The same issue comes up when you want to allow a package to build against either base-1.0 or base 1.1, exposing more features if built with 1.1. We would have something like this: Name: foo Version: 2.0 Build-depends: base >= 1.0 If I build package foo with base 1.0, then I am going to be missing some features from it. The dependency "foo >= 2.0" doesn't fully describe the dependency. We could change it to " foo >= 2.0, base >= 1.1," but I'm not sure that means "I depend on foo 2.0 or later being built with base 1.1 or later" and furthermore, it means that packages' dependencies are not self-contained. - Brian

On Wed, 2006-10-25 at 09:06 -0500, Brian Smith wrote:
Packages should be created in such a way that the set of things exported from the package should not change based on configuration.
Yes. I think I do agree. As an example, as it stands Gtk2Hs is a bunch of packages, however if configurations allowed changing the exposed modules then I could actually package Gtk2Hs all as one single package. That would be a very bad thing. Then as Brian says, there's no way to depend on one of those optional bits. We are introducing a big new feature here, we can start out conservatively and not allow some fields to be used in configuration stanzas. If a real need arises we can review. Duncan

On 25.10 19:08, Duncan Coutts wrote:
We are introducing a big new feature here, we can start out conservatively and not allow some fields to be used in configuration stanzas. If a real need arises we can review.
Would it really help? Packages are very much about social control (issues like namespace allocation), so I am not sure trying to protect users from packagers is a good argument to make things more complicated. An user is equally hurt if 1) an exposed module is missing, 2) it doesn't define the function, 3) it happens to lack critical instances etc. Having dummy modules with dummy function implementations is even worse - the error is only displayed at run-time. - Einar Karttunen

Einar and I talked about this last night, quick summary: Yes, if we were to not allow changing the exposed modules then people could achieve the same effect using CPP. My argument was that we don't need to make it easy and convenient to do these kinds of things that we disapprove of. It should be obvious to a developer that if they're having to do lots of CPP hackery to get this effect that it's not necessarily a good thing. If it's easy to do in the .cabal file then it makes it look like it's an acceptable thing to do. So, in addition to social pressure to not make wierdy packages, you also have to go to greater lengths technically. :-) Duncan On Thu, 2006-10-26 at 03:06 +0300, Einar Karttunen wrote:
On 25.10 19:08, Duncan Coutts wrote:
We are introducing a big new feature here, we can start out conservatively and not allow some fields to be used in configuration stanzas. If a real need arises we can review.
Would it really help? Packages are very much about social control (issues like namespace allocation), so I am not sure trying to protect users from packagers is a good argument to make things more complicated.
An user is equally hurt if 1) an exposed module is missing, 2) it doesn't define the function, 3) it happens to lack critical instances etc. Having dummy modules with dummy function implementations is even worse - the error is only displayed at run-time.

On 26.10 15:49, Duncan Coutts wrote:
Yes, if we were to not allow changing the exposed modules then people could achieve the same effect using CPP.
Can we agree at least on a subset of the functionality to make the simple cases work. It seems to me that there are two real design issues: * Should the clist/flist specification be a simple pure functional language *or* a constraint solving one. * How much should we try to protect users from evil package writers with wrong ideas how to package things. Personally I prefer functional semantics and keeping things simple rather than trying to limit the language because of the things package writers could do with it. A third issue is syntax - but this is not so important. All the ideas on the list have seemed fine, but if we go the functional way we could just make it a subset of Haskell with (==), (&&), (||), not, and Bool and String literals. - Einar Karttunen

On Sun, 2006-10-29 at 10:55 +0200, Einar Karttunen wrote:
On 26.10 15:49, Duncan Coutts wrote:
Yes, if we were to not allow changing the exposed modules then people could achieve the same effect using CPP.
Can we agree at least on a subset of the functionality to make the simple cases work. It seems to me that there are two real design issues:
* Should the clist/flist specification be a simple pure functional language *or* a constraint solving one.
* How much should we try to protect users from evil package writers with wrong ideas how to package things.
We do have to bear in mind how hard it'll be for cabal-get to be able to do dependency analysis. The decisions we make about optional configurations has a big impact on this. It also has a big effect on how easy it is to make 'native' packages for distros which typically don't have extremely sophisticated dependency systems. There's also the important issue of binary packages. We're all used to building from source which gives us a lot of flexibility, but most users expect binary packages. For example Debian and most other commercial distros and Windows of course. It is important that we be able to make sensible binary packages. If the configuration language encourages package authors to go too crazy and one would need 2^n different binary packages then I'd say that we've failed. Remember that the main use case of configurations is just to cope with minor things like modules moving from one package to another or slight differences in the way things are implemented on different platforms or Haskell implementations.
Personally I prefer functional semantics and keeping things simple rather than trying to limit the language because of the things package writers could do with it.
Of course we're doing this already with the split between flags and not allowing 'available' tests in the configuration guards. This is exactly to make it impossible to express certain wrong packaging ideas. I'm much less concerned about whether the exposed modules should be changeable in configuration stanzas. Though again, we should bear in mind things like binary packages.
A third issue is syntax - but this is not so important. All the ideas on the list have seemed fine, but if we go the functional way we could just make it a subset of Haskell with (==), (&&), (||), not, and Bool and String literals.
I don't mind. Propose something concrete. Duncan

On 29.10 14:56, Duncan Coutts wrote:
We do have to bear in mind how hard it'll be for cabal-get to be able to do dependency analysis. The decisions we make about optional configurations has a big impact on this. It also has a big effect on how easy it is to make 'native' packages for distros which typically don't have extremely sophisticated dependency systems.
Why not simply use a single file like: cabal-get.conf that contains flags for packages like: syntax = line+ line = PACKAGE-REGEXP ':' flags flags = <empty> | ['!'] flag flags I don't think there is a sensible way for enabling random flags without the user asking for them. Normally packages should just be built with defaults.
There's also the important issue of binary packages. We're all used to building from source which gives us a lot of flexibility, but most users expect binary packages. For example Debian and most other commercial distros and Windows of course. It is important that we be able to make sensible binary packages. If the configuration language encourages package authors to go too crazy and one would need 2^n different binary packages then I'd say that we've failed.
This is no different than from configure switches for autotools packages - and they don't lead to 2^n different binaries - and there is no technical measure preventing packagers to do evil things depending on the flags with autotools.
Remember that the main use case of configurations is just to cope with minor things like modules moving from one package to another or slight differences in the way things are implemented on different platforms or Haskell implementations.
Yes, and we should concentrate on making it simple and intuitive to do right. Trying to ban the bad ways of doing things seems to complicate things. - Einar Karttunen

On Sun, 2006-10-29 at 18:26 +0200, Einar Karttunen wrote:
On 29.10 14:56, Duncan Coutts wrote:
We do have to bear in mind how hard it'll be for cabal-get to be able to do dependency analysis. The decisions we make about optional configurations has a big impact on this. It also has a big effect on how easy it is to make 'native' packages for distros which typically don't have extremely sophisticated dependency systems.
Why not simply use a single file like: cabal-get.conf that contains flags for packages like:
syntax = line+ line = PACKAGE-REGEXP ':' flags flags = <empty> | ['!'] flag flags
Gentoo does something like this.
I don't think there is a sensible way for enabling random flags without the user asking for them.
Normally packages should just be built with defaults.
Yes. And this should be fine because the package author gets to set the defaults based on aspects of the environment.
There's also the important issue of binary packages. We're all used to building from source which gives us a lot of flexibility, but most users expect binary packages. For example Debian and most other commercial distros and Windows of course. It is important that we be able to make sensible binary packages. If the configuration language encourages package authors to go too crazy and one would need 2^n different binary packages then I'd say that we've failed.
This is no different than from configure switches for autotools packages - and they don't lead to 2^n different binaries - and there is no technical measure preventing packagers to do evil things depending on the flags with autotools.
True, true. There is social pressure not to do silly things. Especially packagers of binary distros tend to put pressure on to make optional parts into whole other packages, or they sometimes do this manually. For example you often get packages which can have N optional backends. In the source build this might be done by using lots of --enable-foo flags. However a binary package either has to pick a fixed set of backends or split the package into multiple binary packages, one for each backend. It'd be good if we didn't need to make binary packagers' lives harder by making them split source packages into multiple binary packages.
Remember that the main use case of configurations is just to cope with minor things like modules moving from one package to another or slight differences in the way things are implemented on different platforms or Haskell implementations.
Yes, and we should concentrate on making it simple and intuitive to do right. Trying to ban the bad ways of doing things seems to complicate things.
Look at it this way: currently you cannot change the set of exposed modules at all. Is there any demand to be able to change them? What is the use case? Is there any reason to add a feature to Cabal to let them be modifiable except that it'd be an easy feature to implement? My point is we're not banning anything, we'd simply be not adding a feature that would be easy to implement. Duncan

On 25.10 09:06, Brian Smith wrote:
Please point out some cases where splitting a package into multiple packages would lead to recursive package dependencies so I can study them.
There are two logging handlers: logger-null and logger-db. Logger-db depends on a database connection. Database connections are provided by postgresql and mysql modules which both depend on a logger being selected. Thus build-depends: logger-null: logger-db: db-any db-any: postgresql || mysql postgresql: logger-db mysql: logger-db
I understand that this would increase the number of packages. But, if it would increase the number of packages 10x, then that means that the original package could be configured with 10 different subsets of functionality. In that case, saying "Build-depends: foo" for that package foo would be almost meaningless. You would need to add some kind of more specific dependency like "Build-depends: foo (Foo.Bar.A, Foo.Bar.C, Foo.Bar.D)" to indicate what modules you need from foo.
16 different subsets are created by e.g. 4 binary choices. e.g. in network-alt I have one choice with 4 alternatives (the backend) and the choice whether to use fps. Then there is debugging. That is 4*2*2 = 16 choices. And only the FPS one affects API.
Packages should be created in such a way that the set of things exported from the package should not change based on configuration. If some features are only valid under one configuration, then they should be factored out into a seperate module and then a seperate package. For example, GHC-specific features should be factored out into a separate package, Windows-specific features should be factored out into a separate package, etc. More-or-less, that is how the hierarchical libraries are designed at the module level.
Except this is not true even for the base-package. See e.g. Control.Concurrent. Another problem is that they usually use internals of the package that one does not which to export.
If I build package foo with base 1.0, then I am going to be missing some features from it. The dependency "foo >= 2.0" doesn't fully describe the dependency. We could change it to " foo >= 2.0, base >= 1.1," but I'm not sure that means "I depend on foo 2.0 or later being built with base 1.1 or later" and furthermore, it means that packages' dependencies are not self-contained.
And package authors should take care on not doing evil things. There are very many Haskell packages that do all kinds of magic with CPP depending e.g. on compiler version. - Einar Karttunen

On Tue, 2006-10-24 at 21:45 -0500, Brian Smith wrote:
(sorry, I responded to the wrong list)
On 10/24/06, Duncan Coutts
wrote: On the other hand, in Gtk2Hs I know one case where we do this. We have a Graphics.UI.Gtk.Cairo api module that is only included if Gtk was built against Cairo. In any case it could be faked by using cpp to just not export anything rather than not having the module exposed at all. So it's not clear that it's worth banning. Or maybe making it slightly harder is worth it so that people don't get in the habit. Couldn't you split this into Gtk and Gtk-Cairo packages, where the latter is only built if Cairo is available?
Yes I could and that's probably the right thing to do.
Similarly, in your GUI example, couldn't you have seperate foo and foo-gui packages, and only build the foo-gui package if the GUI libraries are available?
I'm not so sure about that one.
Otherwise, how can you say "I depend on the Gtk package being built with Cairo support" and "I depend on the GUI portion of the foo package?"
Indeed. Duncan
participants (3)
-
Brian Smith
-
Duncan Coutts
-
Einar Karttunen