Providing a smooth default user experience

Hi all, Sensible defaults are important to provide a smooth user experience, especially for first-time users. There are a few areas where I think cabal could improve its default behavior. In particular, here are a couple of changes I would like to make: *cabal build should imply cabal install --only-dependencies * If you're currently working on a package, the right [1] way to build it is as follows: cabal install --only-dependencies cabal build (Note that in HEAD cabal build implies cabal configure so that step is no longer necessary, unless you need set some configure flags.) However, this is unintuitive and repetitive and many users end up using cabal install instead. The reasons I've heard for not having build imply installing dependencies is that users might not want packages to be downloaded from the internet, unless they explicitly use cabal install. While that's a fair point, I think it should be an opt-out rather than an opt-in because: - Users will end up have to install the dependencies anyway and there's typical no other options than installing them from Hackage. - Many users use cabal install instead of cabal build, for the reasons given above, making it a moot point. Proposal: add a --install-dependencies flag to cabal build that defaults to True. Once we start installing dependencies by default, the very first run of cabal build may take a long time, especially if sandboxing is used, so I think we should output the following message before installing dependencies: "Installing dependencies. This may take a long time if this is the first time you build this package." *Sandboxing should be used by default* This follows the "make it correct, then make it fast" principle. Sandboxing helps with a certain class of build problems, namely problems due to two different builds overwriting each others' dependencies in the shared package database. This problem shows up as a dangerously sounding cabal warning message, mentioning the --force-reinstalls flag. Sandboxing is an imperfect solution to this problem, requiring more rebuilding of packages than strictly necessary. A final solution would involve something like a Nix-style, append-only package database. The Nix solution is being worked on, as part of GSoC, but it's a difficult problem and it requires more wide-reaching changes (e.g. to ghc, ghc-pkg, ghci, and cabal). Since sandboxing is working today (with a few minor tweaks yet to be done) and it can be transparently replaced with a better solution once we have one, I think we should enable it by default in 1.18. Since sandboxing will result in more rebuilding, we should also enabled parallel builds by default, as they typically speed up builds by a factor of 2. Finally I think we need to improve messaging. We could use the same messaging as above i.e. "Installing dependencies. This may take a long time if this is the first time you build this package." Adding sandboxing by default also makes it easier to depend on unreleased versions of packages, as it has an add-source <dir> sub-command for managing those. *We should add a cabal run command* This proposal will only affect a small group of users, but will give those users a better user experience and hopefully encourage them to use cabal the right way. When developing e.g. web apps using Snap, the user needs to build and run an executable. You can do this today by running cabal build dist/build/my-exe/my-exe but e.g. the Snap documentation instead encourages users to do cabal install my-exe Perhaps because it's shorter and requires less explanation of where cabal puts its build output. I think we could improve this use case by introducing a new command, cabal run, with the following parameters: cabal run <executable> <args> which would run cabal build dist/build/<executable>/<executable> <args> Comments welcome! Cheers, Johan 1. The reason this is the right way is that you don't want to litter your shared package database with unreleased packages, as other packages might be built against these unreleased packages by misstake.

On 10/31/2012 06:22 PM, Johan Tibell wrote:
Hi all,
Sensible defaults are important to provide a smooth user experience, especially for first-time users. There are a few areas where I think cabal could improve its default behavior. In particular, here are a couple of changes I would like to make:
*cabal build should imply cabal install --only-dependencies * [--snip--] The reasons I've heard for not having build imply installing dependencies is that users might not want packages to be downloaded from the internet, unless they explicitly use cabal install. While that's a fair point, I think it should be an opt-out rather than an opt-in because:
It might be an option to do what Maven (shudder) does here: Have an explicit "offline" mode (switchable by config or cmdline option) which simply blocks any online activity with an error message.
- Users will end up have to install the dependencies anyway and there's typical no other options than installing them from Hackage. - Many users use cabal install instead of cabal build, for the reasons given above, making it a moot point.
Proposal: add a --install-dependencies flag to cabal build that defaults to True.
+1. [--snip--]
*Sandboxing should be used by default*
+1.
This follows the "make it correct, then make it fast" principle. Sandboxing helps with a certain class of build problems, namely problems due to two different builds overwriting each others' dependencies in the shared package database. This problem shows up as a dangerously sounding cabal warning message, mentioning the --force-reinstalls flag.
That, and you end up with broken packages due to no fault of your own (using the default mode). That's simply bad from a usability perspective.
Sandboxing is an imperfect solution to this problem, requiring more rebuilding of packages than strictly necessary. A final solution would involve something like a Nix-style, append-only package database. The Nix solution is being worked on, as part of GSoC, but it's a difficult problem and it requires more wide-reaching changes (e.g. to ghc, ghc-pkg, ghci, and cabal). Since sandboxing is working today (with a few minor tweaks yet to be done) and it can be transparently replaced with a better solution once we have one, I think we should enable it by default in 1.18.
(Drools about the prospect of true Nix-style package database -- hope's to hoping that happens at some point.)
*We should add a cabal run command*
+1.

Hi Johan,
On Wed, Oct 31, 2012 at 6:22 PM, Johan Tibell
cabal build should imply cabal install --only-dependencies
+1
The Nix solution is being worked on, as part of GSoC
Is it still being worked on? I thought that the development stalled after the GSoC period ended.
Since sandboxing is working today (with a few minor tweaks yet to be done) and it can be transparently replaced with a better solution once we have one, I think we should enable it by default in 1.18.
Will that be the next cabal-install release or the one after that?
We should add a cabal run command
+1 -- () ascii ribbon campaign - against html e-mail /\ www.asciiribbon.org - against proprietary attachments

On Wed, Oct 31, 2012 at 2:52 PM, Mikhail Glushenkov < the.dead.shall.rise@gmail.com> wrote:
On Wed, Oct 31, 2012 at 6:22 PM, Johan Tibell
wrote:> Since sandboxing is working today (with a few minor tweaks yet to be done) and it can be transparently replaced with a better solution once we have one, I think we should enable it by default in 1.18.
Will that be the next cabal-install release or the one after that?
The next one. -- Johan

Am 31.10.2012 18:22, schrieb Johan Tibell:
*We should add a cabal run command* [snip]
I think we could improve this use case by introducing a new command, cabal run, with the following parameters:
cabal run <executable> <args>
which would run
cabal build dist/build/<executable>/<executable> <args>
I like this idea, but this is for executables only. Recently, I had to add a MIN_VERSION macro to my code because of the old-time / time change in directory, but couldn't test the library in ghci because the macro was not defined. I discovered that configuring ghci with :set -optP-include -optPdist/build/autogen/cabal_macros.h tells ghci about the macro, but I find this even more cumbersome than dist/build/<executable>/<executable>. So, if I'm not missing something, it may also be comfortable to add a cabal ghci command which tells ghci about cabal's configuration. Regards, Björn

Recently, I had to add a MIN_VERSION macro to my code because of the old-time / time change in directory, but couldn't test the library in ghci because the macro was not defined.
I discovered that configuring ghci with
:set -optP-include -optPdist/build/autogen/cabal_macros.h
tells ghci about the macro, but I find this even more cumbersome than dist/build/<executable>/<executable>.
So, if I'm not missing something, it may also be comfortable to add a
cabal ghci
command which tells ghci about cabal's configuration.
You can put the required options in a .ghci file in you project root. I use [3] as a starting point for new projects, [2] and [3] are real world examples. `cabal ghci` could still be useful, but I think a general solution is not trivial. It would probably need to accept qualified targets, e.g. `ghci test:properties` to start ghci in a way suitable for a test-suite with the name "properties". Moreover, it would be awesome if it would regenerate generated source files on :reload. I'm not sure if this is feasible without changes to GHCi, but a custom macro, e.g. :cabal-reload could still work. Cheers, Simon [1] http://hpaste.org/77144 [2] https://github.com/ghc/haddock/blob/ghc-7.6/.ghci [3] https://github.com/sol/doctest-haskell/blob/master/.ghci

On Fri, Nov 02, 2012 at 11:25:11AM +0100, Simon Hengel wrote:
Recently, I had to add a MIN_VERSION macro to my code because of the old-time / time change in directory, but couldn't test the library in ghci because the macro was not defined.
I discovered that configuring ghci with
:set -optP-include -optPdist/build/autogen/cabal_macros.h
tells ghci about the macro, but I find this even more cumbersome than dist/build/<executable>/<executable>.
So, if I'm not missing something, it may also be comfortable to add a
cabal ghci
command which tells ghci about cabal's configuration.
You can put the required options in a .ghci file in you project root. I use [3] as a starting point for new projects, [2] and [3] are real world examples.
`cabal ghci` could still be useful, but I think a general solution is not trivial. It would probably need to accept qualified targets, e.g. `ghci test:properties` to start ghci in a way suitable for a test-suite with the name "properties".
Moreover, it would be awesome if it would regenerate generated source files on :reload. I'm not sure if this is feasible without changes to GHCi, but a custom macro, e.g.
:cabal-reload
could still work.
Seems that there is a ticket for that: https://github.com/haskell/cabal/issues/375 Cheers, Simon

On Fri, 2012-11-02 at 11:25 +0100, Simon Hengel wrote:
Recently, I had to add a MIN_VERSION macro to my code because of the old-time / time change in directory, but couldn't test the library in ghci because the macro was not defined.
I discovered that configuring ghci with
:set -optP-include -optPdist/build/autogen/cabal_macros.h
tells ghci about the macro, but I find this even more cumbersome than dist/build/<executable>/<executable>.
So, if I'm not missing something, it may also be comfortable to add a
cabal ghci
command which tells ghci about cabal's configuration.
You can put the required options in a .ghci file in you project root. I use [3] as a starting point for new projects, [2] and [3] are real world examples.
`cabal ghci` could still be useful, but I think a general solution is not trivial. It would probably need to accept qualified targets, e.g. `ghci test:properties` to start ghci in a way suitable for a test-suite with the name "properties".
Yes, we have been working on this. Last weekend I was updating the code for doing the qualified target stuff cabal build exe:foo etc.
Moreover, it would be awesome if it would regenerate generated source files on :reload. I'm not sure if this is feasible without changes to GHCi, but a custom macro, e.g.
:cabal-reload
could still work.
The GSoC project that started this off did that, and the necessary changes are in ghc now. Duncan

Duncan,
Moreover, it would be awesome if it would regenerate generated source files on :reload. I'm not sure if this is feasible without changes to GHCi, but a custom macro, e.g.
:cabal-reload
could still work.
The GSoC project that started this off did that, and the necessary changes are in ghc now.
That is interesting. I'd be interested in how exactly that works. Is there a place where I can read about it? Or if not, can you point me to the related commits? Cheers, Simon

On Fri, 2012-11-02 at 16:52 +0100, Simon Hengel wrote:
Duncan,
Moreover, it would be awesome if it would regenerate generated source files on :reload. I'm not sure if this is feasible without changes to GHCi, but a custom macro, e.g.
:cabal-reload
could still work.
The GSoC project that started this off did that, and the necessary changes are in ghc now.
That is interesting. I'd be interested in how exactly that works. Is there a place where I can read about it? Or if not, can you point me to the related commits?
http://lambdasandwich.blogspot.co.uk/2011/08/ending-gsoc.html For the changes to ghci see the ghc git repo. Look for stuff related to .ghci file handling. That was the main extension needed, so we could specify a .ghci file on the command line. Duncan

Hi Duncan,
That is interesting. I'd be interested in how exactly that works. Is there a place where I can read about it? Or if not, can you point me to the related commits?
http://lambdasandwich.blogspot.co.uk/2011/08/ending-gsoc.html
For the changes to ghci see the ghc git repo. Look for stuff related to .ghci file handling. That was the main extension needed, so we could specify a .ghci file on the command line.
Thanks a lot for the pointers. I looked at [1] (specifically at mkDotGhci), but as far as I can tell this does not work anymore. Here is what I tried: ghci> :def! foo (\_ -> return "23") ghci> :foo 23 ghci> :def! reload (\_ -> return "23") ghci> :reload Ok, modules loaded: none. It seems that builtins always take precedence over user defined commands. I tried this with GHC 7.2.2, GHC 7.4.2 and GHC 7.6.1. It works with GHC 7.0.4. But even here the code has issues, because it does an :undef so that it can call the original :reload. But after that our custom :reload is gone. So it works, but only once. This is easily fixed, e.g. the following works with GHC 7.0.4: ghci> :def! __reload__ (\_ -> return ":!echo 'do-cabal-specific-stuff'\n:undef reload\n:reload\n:def reload (\\_ -> return \":__reload__\")") ghci> :def! reload (\_ -> return ":__reload__") ghci> :reload do-cabal-specific-stuff Ok, modules loaded: none. ghci> :reload do-cabal-specific-stuff Ok, modules loaded: none. I think if we want to redefine :reload we need the :def semantics we had in GHC 7.0.4. Should I open a GHC ticket? Cheers, Simon [1] http://code.haskell.org/~bogiebro/cabal/cabal/cabal/Distribution/Simple/GHC....

Hi,
On Fri, Nov 2, 2012 at 10:48 AM, Björn Peemöller
So, if I'm not missing something, it may also be comfortable to add a
cabal ghci
command which tells ghci about cabal's configuration.
There was a "cabal repl" GSoC project last year. The patches haven't been merged yet, since they require some reworking. Duncan knows more about the current state of affairs. -- () ascii ribbon campaign - against html e-mail /\ www.asciiribbon.org - against proprietary attachments

On Wed, 2012-10-31 at 10:22 -0700, Johan Tibell wrote:
Hi all,
Sensible defaults are important to provide a smooth user experience, especially for first-time users. There are a few areas where I think cabal could improve its default behavior. In particular, here are a couple of changes I would like to make:
*cabal build should imply cabal install --only-dependencies * If you're currently working on a package, the right [1] way to build it is as follows:
cabal install --only-dependencies cabal build
I've been thinking along similar lines recently. We should be thinking about package environments (which spans multiple packages) rather than individual packages, and the UI should reflect that. Right now it's very much centred on individual packages, not collections. So "cabal configure" should configure/reconfigure the package environment, not the individual package. It should make an install plan for the current environment (which at minimum is a single target package and its dependencies but could be several packages in the same env). Then of course executing that install plan by building any of the targets should go and build deps as necessary. Of course from a UI pov, we have to make it clear what's going to happen. When you configure an environment, it needs to say that it'll involve installing several things locally. That's also the appropriate point to freeze (or partially freeze) a package environment to give a reproducible build. I think when changing the packages in an environment, we should always enforce complete consistency of dependencies. So you know straight away if you can add two packages to the same environment, and not let people get into the situation of broken packages. You can change stuff and rebuild, but we should always have an install plan for the whole lot, not just a subset. Duncan

On Fri, Nov 2, 2012 at 8:43 AM, Duncan Coutts
*cabal build should imply cabal install --only-dependencies * If you're currently working on a package, the right [1] way to build it is as follows:
cabal install --only-dependencies cabal build
I've been thinking along similar lines recently. We should be thinking about package environments (which spans multiple packages) rather than individual packages, and the UI should reflect that. Right now it's very much centred on individual packages, not collections.
So "cabal configure" should configure/reconfigure the package environment, not the individual package. It should make an install plan for the current environment (which at minimum is a single target package and its dependencies but could be several packages in the same env). Then of course executing that install plan by building any of the targets should go and build deps as necessary.
Should I interpret this as you're in favor of the first steps towards such a change, as described above (automatically install dependencies), with a flag to opt out? -- Johan

Hi Johan, On Wed, Oct 31, 2012 at 10:22:36AM -0700, Johan Tibell wrote:
*Sandboxing should be used by default*
I'm a little bit late on this one. But I'm somewhat skeptical here. As I understand it, the sandboxing feature is not yet released. I think there is a chance that the first version will not cover all use cases. So personally I think it is a better approach to first release the feature, and give people time to try whether there use case are covered. For context: I run my test in GHCi. Sometimes this requires some work, but I have a working setup for all my projects. For me (and probably for others who are serious about TDD), the sandbox feature is only useful if running tests within GHCi works. Cheers, Simon

Hi,
On Thu, Nov 29, 2012 at 3:45 PM, Simon Hengel
So personally I think it is a better approach to first release the feature, and give people time to try whether there use case are covered.
The idea is to put out a release candidate some time before the final release to give people an opportunity to voice their concerns.
For context: I run my test in GHCi. Sometimes this requires some work, but I have a working setup for all my projects. For me (and probably for others who are serious about TDD), the sandbox feature is only useful if running tests within GHCi works.
This will probably be covered by the "cabal repl" feature that Duncan is working on. -- () ascii ribbon campaign - against html e-mail /\ www.asciiribbon.org - against proprietary attachments

On Thu, Nov 29, 2012 at 04:33:05PM +0100, Mikhail Glushenkov wrote:
So personally I think it is a better approach to first release the feature, and give people time to try whether there use case are covered.
The idea is to put out a release candidate some time before the final release to give people an opportunity to voice their concerns.
Sounds good :)

Hi Simon,
On Thu, Nov 29, 2012 at 6:45 AM, Simon Hengel
Hi Johan,
On Wed, Oct 31, 2012 at 10:22:36AM -0700, Johan Tibell wrote:
*Sandboxing should be used by default*
I'm a little bit late on this one. But I'm somewhat skeptical here. As I understand it, the sandboxing feature is not yet released. I think there is a chance that the first version will not cover all use cases.
So personally I think it is a better approach to first release the feature, and give people time to try whether there use case are covered.
We may very well end up doing this. There's no rush to make it default. We can make a release with opt-in sandboxes and decide three months later if we want to make it the default. -- Johan

On Thu, Nov 29, 2012 at 07:54:34AM -0800, Johan Tibell wrote:
We may very well end up doing this. There's no rush to make it default. We can make a release with opt-in sandboxes and decide three months later if we want to make it the default.
Nice. So I guess the idea is that we will have a release candidate (as Mikhail suggested). If there are major issues that we can't get fixed before the release, we make it opt-in? Cheers, Simon

On Thu, Nov 29, 2012 at 8:20 AM, Simon Hengel
On Thu, Nov 29, 2012 at 07:54:34AM -0800, Johan Tibell wrote:
We may very well end up doing this. There's no rush to make it default. We can make a release with opt-in sandboxes and decide three months later if we want to make it the default.
Nice.
So I guess the idea is that we will have a release candidate (as Mikhail suggested). If there are major issues that we can't get fixed before the release, we make it opt-in?
We might make it opt-in in any case, since we cannot really test everyone's usage patterns. I think what we'll do is to make it opt-in and at the same time announce our intentions to make it default and encourage people to try it out for an extended period of time. -- Johan

On Thu, Nov 29, 2012 at 09:01:13AM -0800, Johan Tibell wrote:
On Thu, Nov 29, 2012 at 8:20 AM, Simon Hengel
wrote: On Thu, Nov 29, 2012 at 07:54:34AM -0800, Johan Tibell wrote:
We may very well end up doing this. There's no rush to make it default. We can make a release with opt-in sandboxes and decide three months later if we want to make it the default.
Nice.
So I guess the idea is that we will have a release candidate (as Mikhail suggested). If there are major issues that we can't get fixed before the release, we make it opt-in?
We might make it opt-in in any case, since we cannot really test everyone's usage patterns. I think what we'll do is to make it opt-in and at the same time announce our intentions to make it default and encourage people to try it out for an extended period of time.
Ok, makes sense. I would assume that implying `cabal install --only-dependencies` on `cabal build` is only sane if sandboxing is used. So we would defer that too? Cheers, Simon
participants (6)
-
Bardur Arantsson
-
Björn Peemöller
-
Duncan Coutts
-
Johan Tibell
-
Mikhail Glushenkov
-
Simon Hengel