# Cabal UX discussion

**URL:** <https://discourse.haskell.org/t/cabal-ux-discussion/4502>\
**Category:** Uncategorized\
**Created:** [May 9, 2022, 12:00am UTC](https://discourse.haskell.org/t/cabal-ux-discussion/4502 "2022-05-09T00:00:45Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![sclv](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/sclv/32/71_2.png) [@sclv](https://discourse.haskell.org/u/sclv)\
**Post date:** [May 9, 2022, 12:00am UTC](https://discourse.haskell.org/t/cabal-ux-discussion/4502/1 "2022-05-09T00:00:45Z")

</div>

> [@Modularizing GHC, do we want an HFTP?](http://discourse.haskell.org/t/modularizing-ghc-do-we-want-an-hftp/4022/9):
>
> FYI I’ve stopped submitting UX issues to cabal-install because only UX issues that align with subjective interests of maintainers seem to get through.

I looked through the cabal issue tracker and assuming you use the same github nick, I found no issues at all submitted by you to cabal-install?

In any case, with cabal, as with all projects, only issues which make some degree of sense to maintainers and which are feasible in the scope of the existing structure and codebase will get through. But in the cabal case, the current batch of maintainers has worked pretty hard to reach out and address many usability issues which are recognized to hit newer users rather than “experts” such as themselves, and there is also new blood amongst maintainers in terms of people with different ux expectations, so ux issues typically get a broad spread of discussion rather than a single firm “yes” or “no”.

---

<div class="post-metadata">

**Author:** ![ParetoOptimalDev](https://avatars.discourse-cdn.com/v4/letter/p/b782af/32.png) [@ParetoOptimalDev](https://discourse.haskell.org/u/ParetoOptimalDev)\
**Post date:** [May 9, 2022, 5:42am UTC](https://discourse.haskell.org/t/cabal-ux-discussion/4502/2 "2022-05-09T05:42:57Z")

</div>

> [@sclv](#):
>
> But in the cabal case, the current batch of maintainers has worked pretty hard to reach out and address many usability issues which are recognized to hit newer users rather than “experts” such as themselves, and there is also new blood amongst maintainers in terms of people with different ux expectations, so ux issues typically get a broad spread of discussion rather than a single firm “yes” or “no”.

Maybe its changed, but the big one I had in mind was this one:

> <https://github.com/haskell/cabal/issues/5696>
>
> \# Overview
> 
> Provide the most beginner friendly cabal-install CLI possible. Thi…s means that the \`cabal\` commands by default (read: no arguments) should do the thing that beginners expect to get them to do, from zero to a Haskell program they can run.
> 
> \_Note: This is related, but an expansion in scope from https://github.com/haskell/cabal/issues/5661\_
> 
> \## Example “Hello World”
> 
> Here are the commands that a beginner should need to run to get a working “Hello World” Haskell program that will build and run now, and will always build in the future, regardless of global system changes (like ghc version updates):
> 
> \`\`\`
> mkdir myfirstproject && cd myfirstproject
> cabal init
> cabal run
> \`\`\`
> 
> That’s it. No interactive prompt asking them a bunch of questions about licences; if they want a library, executable, or library and executable; if they want a separate \`src\` directory; base language; or anything else.
> 
> \## Whose developer experience does this improve?
> Beginners. Let’s make it as easy as possible for someone new to the language to get started and hacking on a Haskell program. The easier the onboarding, the better the adoption rate. You could argue that you could invoke ghc directly but you quickly need to start using cabal when you want to start using other packages, so let’s not make them learn something new twice.
> 
> Casual users. I often find myself with some idea I want to play with and just want the simplest way to get a basic project up and running. The fewer commands and CLI arguments I need to remember the better.
> 
> \_\*\*”But what about the power users?”\*\*\_
> 
> I’ll make the same point I made in #5661, if you’re a power user, you know your way around cabal anyways. If you want to create a package interactively you can run \`cabal init -i\` (or \`--interactive\`), or maybe just specify the specific arguments you want to \`cabal init\` yourself. We should make the simplest experience the easiest in order to appeal to the widest audience possible.
> 
> This old default behaviour can also be re-enabled by setting \`interactive-init: True\` (module bikeshed) in \`~/.cabal/config\` for those that want the old interactive-by-default workflow.
> 
> \# Changes
> 
> Let me first present a summary of the changes, I’ll explain the rational of them below.
> 
> \- \[x\] \`cabal init\` default to not-interactive (\`-n\`), and \`--interactive-init, -i\` is added (#5902).
> - Implemented: First question is to initialize a simple project (also available as \`--simple\`)
> - Provide both \`--interactive\` and \`--non-interactive\` flags (#5864)
> \- \[x\] \`cabal init\` defaults to \`--exe\` \_(edit: previously \`--libandexe\`)\_ (#5854)
> \- \[\] \`cabal init\` pins the \`ghc\` version via \`with-compiler\` in \`cabal.project\` for executables
> \- \[x\] \`cabal run\` is \`cabal v2-run\` (aka \`cabal new-run\`) (#5800)
> \- \[x\] (minor) \`--exe\` and \`--lib\` as shorthands for \`--is-executable\` and \`--is-library\` (#5759)
> 
> \## Default to non-interactive
> 
> When someone gets started with Haskell and initialize a project they’re confronted with a large list of questions about what licence they want; what category their package falls into; if they want a binary, executable, or both; if they want their main as a \`.hs\` or \`.lhs\` file; where they want their source directory to be, and what “base language” they want.
> 
> To a beginner, the majority (IMHO, all) of these questions are confusing at best, all they really want is to start hacking on a Haskell file. By defaulting to non-interactive, the base command gives them what they expect, a minimally configured package that they can run, edit a file, and run it again.
> 
> The existing interactive behaviour would still be accessible via an \`--interactive, -i\` flag. If you’re already familiar with cabal then learning one new flag for interactively creating a package is incredible low overhead. Sure, you may need to change your workflow \_slightly\_, but I think that’s a pretty low cost to pay for making a beginner's experience better.
> 
> Additionally, the old default behaviour can also be re-enabled by setting \`interactive-init: True\` (module bikeshed) in \`~/.cabal/config\` for those that want the old interactive-by-default workflow.
> 
> \### (alternative) "Would you like to initialize a simple project?" as first questions
> 
> \_Note: This was implemented in #5707.\_
> 
> From the suggestion from @gbaz below, another option is to keep \`--interactive\` as the default, but move the "What type of project?" question to be the first question, and add a new choice "Executable (Simple Project)" as the default which will skip the rest of the interactive menus and create a bare bones executable. 
> 
> \## Default to executable (with library)
> 
> Once again, to offer a simple default initialization behaviour what we really want is a binary. This is actually inline with what Rust switched to in version 1.25 (\[blog\](https://blog.rust-lang.org/2018/03/29/Rust-1.25.html), see “Cargo Features” section), and they made an incredibly good observation:
> 
> \_”Cargo’s CLI has one really important change this release: \`cargo new\` will now default to generating a binary, rather than a library… If you don’t pass one of these flags, in previous versions of Cargo, it would default to \`--lib\`. We made this decision because each binary (often) depends on many libraries, and so the library case is more common. However, this is incorrect; each library is depended upon by many binaries. Furthermore, when getting started, what you often want is a program you can run and play around with. It’s not just new Rustaceans though; even very long-time community members have said that they find this default surprising. As such, we’re changing it.”\_
> 
> ~Since its good practice to place all of the actually code in a library and have a "dumb main" to ease testing and allow for usage outside of your executable, we initialize a library and executable.~
> 
> Initializing both a library and executable with reasonable defaults and directory structure is now handled by the "simple project" initialization, \`cabal init --simple\`.
> 
> \## cabal init pins the ghc version for executables
> 
> For the full discussion see #5661.
> 
> In summary, not pinning the ghc version can result in a working build one day failing to build another day due to a change in global system state (such as the \`ghc\` on PATH).
> 
> \## cabal run is cabal v2/new-run
> 
> In summary, we want the “new build” to be the default for all the reasons outlined \[here\](https://cabal.readthedocs.io/en/latest/nix-local-build-overview.html). This is planned for the cabal-install 3.0 release.
> 
> \## (minor) \`--exe\` and \`--lib\` as shorthands
> 
> This obviously isn’t critical, the current versions are just really verbose and not inline with other tools.
> 
> \# Backwards Compatibility
> 
> \*\*Default to non-interactive\*\*
> 
> \_In theory\_ this is not backwards compatible since previously running \`cabal init\` with no arguments would drop you into interactive mode, but after the change it would select sane defaults for you.
> 
> \_In practice\_, this mode would not be used in scripts anyways so this is unlikely to cause issues for any automation, since those scripts would explicitly spell out the arguments to \`cabal init\`.
> 
> If in the past you relied on the default interactive behaviour when manually creating a package you can either use the new \`--interactive\` (or \`-i\`) flag, or just edit the \`.cabal\` file manually. 
> 
> \*\*Default to executable\*\*
> 
> Technically not backwards compatible. The current \`cabal init -n\` behaviour creates a library, so anyone who previously ran the command in non-interactive mode without manually specifying an \`--is-xyz\` flag would get different behaviour. I would imagine this isn’t a common case, and those that were relying on the behaviour could slightly adjust their workflows.
> 
> \*\*cabal init pins ghc-version\*\*
> 
> See discussion in #5661.
> 
> \*\*cabal run is cabal v2/new-run\*\*
> 
> I don’t think there’s anyone who doesn’t want this. The backwards compatibility of that switch is out of scope here.
> 
> \*\*(minor) \`--exe\` and \`--lib\` as shorthands\*\*
> 
> Simply introducing new aliases, nothing breaking here.
> 
> \# Timeline / Milestone
> 
> I would like to target the cabal-install 3.0 release since this will already include substantial changes (namely, defaulting to new-build). If we're going to make "breaking" changes to the CLI it makes sense to go out in the next major version.
> 
> \# Edit History
> 
> \*\*2018-11-20 9:15PST\*\*
> 
> \- Add "Default to non-interactive" alternative
> \- Add "Timeline / Milestone" section
> 
> \*\*2018-11-20 17:30PST\*\*
> 
> \- Add \`interactive-init\` option to \`~/.cabal/config\`
> 
> \*\*2019-01-20 11:40PST\*\*
> 
> \- Default to \`--exe\` instead of \`--lib-and-exe\`
> 
> /cc @23Skidoo @hvr

This one turned out well after a lot of convincing abd is pretty old, so I guess I should stop counting it.

Another is any related to nix integration like:

> <https://github.com/haskell/cabal/issues/4646>
>
> At least, the \`cabal-install\` one can compile with \[the current latest release t…ag\](https://github.com/haskell/cabal/releases/tag/Cabal-v2.0.0.2) (with GHC 8.2.1) does not support it.

While ljoking for examples, I saw proof enough of what you say about things being seriously considered by current maintainers [here](https://github.com/haskell/cabal/issues/7548) on a large issue.

So happily, I’ll concede it appears you are right and I will resume reporting any Cabal issues I encounter.

---

<div class="post-metadata">

**Author:** ![sclv](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/sclv/32/71_2.png) [@sclv](https://discourse.haskell.org/u/sclv)\
**Post date:** [May 9, 2022, 7:00pm UTC](https://discourse.haskell.org/t/cabal-ux-discussion/4502/3 "2022-05-09T19:00:03Z")

</div>

On the last topic (nix) it often ends up (as on that ticket) that key people involved in haskell nix work are solicited and weigh in and their comments amount to “we really don’t need anything from cabal here.” The one thing that there has been ongoing work on that is relevant to nix, but much else besides, is ensuring that cabal v2 commands have a genuinely “offline” mode that can restrict them to a much more externally fixed package universe.

---

<div class="post-metadata">

**Author:** ![angerman](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/angerman/32/892_2.png) [@angerman](https://discourse.haskell.org/u/angerman)\
**Post date:** [May 10, 2022, 1:54am UTC](https://discourse.haskell.org/t/cabal-ux-discussion/4502/4 "2022-05-10T01:54:11Z")

</div>

@sclv there’s only two things that (in my haskell nix integration) are a bit cumbersome to deal with cabal. These are

- excessive requirement to pass constraints to prevent cabal from solving. I know the set of packages I want this to be built against with Setup.hs, and there is only one package instance for each package in the package db, however Setup.hs keeps running the solver, unless I pass constraints for each package. Something like: please just use this package-db, and don’t try to solve anything would be a helpful flag to Setup.hs’s interface.
- plan.json only containing a subset of information. If it would contain the full build plan this would be helpful. (Or a separate cabal solve tool, that takes a GHC description (ideally not interrogate GHC), a cabal.project file, and a hackage index state), and produce the dependency tree.

The reason is as follows: what we use `cabal-install` to solve for the project. And then use that information to provision a proper package database, which we then use to build the project using the lower level `Setup.hs`. This approach allows us to trivially support cross compilation.

---

<div class="post-metadata">

**Author:** ![Ericson2314](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/ericson2314/32/1026_2.png) [@Ericson2314](https://discourse.haskell.org/u/Ericson2314)\
**Post date:** [May 10, 2022, 12:52pm UTC](https://discourse.haskell.org/t/cabal-ux-discussion/4502/5 "2022-05-10T12:52:02Z")

</div>

~~Am I correct in recalling that someone has moderator powers to split the thread? I too would like to discuss Cabal things, but it’s a bit off topic from this thread :), I suppose I _would_ like to make an actual HFTP at some point if the contributions kicked off by the paper (GSOC and otherwise) go well, so it would be good if it didn’t stray too much :).~~

Done, thanks @jaror!

* * *

I think @angerman’s list is good, but I also want a black-box way for an external tool to provide package sources, so rather than using things like `active-repositories` `source-repository-package` I can build the exact index/repository I want with Nix and then feed it to `cabal-install`. My coworkers and I are very fond of how we can pin inputs for all languages in a uniform way with Nix. The ability to use that in conjunction with package manager solvers (like `haskell.nix` leverages) is a goldilox best-of-both-worlds we’ve long wanted!

---

<div class="post-metadata">

**Author:** ![jaror](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/jaror/32/3271_2.png) [@jaror](https://discourse.haskell.org/u/jaror)\
**Post date:** [May 10, 2022, 1:14pm UTC](https://discourse.haskell.org/t/cabal-ux-discussion/4502/6 "2022-05-10T13:14:36Z")

</div>

> [@Ericson2314](#):
>
> Am I correct in recalling that someone has moderator powers to split the thread?

Granted 🙂

Note that normal users can post their own reply in a new thread, see: [Hello, foundation! - #24 by jaror](http://discourse.haskell.org/t/hello-foundation/1503/24)

---

<div class="post-metadata">

**Author:** ![fendor](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/fendor/32/376_2.png) [@fendor](https://discourse.haskell.org/u/fendor)\
**Post date:** [May 11, 2022, 1:34pm UTC](https://discourse.haskell.org/t/cabal-ux-discussion/4502/7 "2022-05-11T13:34:02Z")

</div>

> [@angerman](#):
>
> plan.json only containing a subset of information

Out of curiosity, what information is missing?
