State of the Cabal - Q1+Q2/2021

That already exists, sorta. You can use stackages cabal.config as a config or a freeze file or use the more sophisticated stack2cabal.

The only thing missing is this:

And that’s exactly the problem that will lead us to no unified build tool. People having different expectations how something should work.

Stackage is really not a “repository”. It is just a set of constraints.

3 Likes

That already exists, sorta. You can use stackages cabal.config as a config or a freeze file or use the more sophisticated stack2cabal.

I think stack is great, but it is another layer of complexity over cabal which I think brings its own set of downsides. This is why I am keen to switch back to cabal.

I have attempted to switch to cabal-install using freeze files (not sure about stack2cabal) to mimic stackage, but I found the hoop jumping required made it not worth it. Plus cabal-install lacks some features that I like from stack.

My hope is with this announcement some of these features can be added to cabal-install, ie. file-watch and auto adding modules to the cabal file. And yeah, ideally stackage support :slight_smile:

Anyway, just my 2c. Either way really excited about this announcement.

2 Likes

There are very good arguments against this that indicate a) it’s not cabal’s job and b) can be easily implemented the unix way by another tool (or your IDE), which has been done already.

2 Likes

If cabal followed the unix philosophy, it would be a tool that takes a list of direct dependencies on stdin and dumps a full dependency tree on stdout. :slight_smile: (Pipe it to tsort to sort them topologically!!)

I’m all for letting the motivated individuals behind the two tools to continue following their own ideals, and I do think those ideals have some differences. But whether or not one is more unixy than the other is not an actionable talking point. :stuck_out_tongue:

Edit: hmmm now I’m wondering what a truly unix-like suite of tools for building haskell would actually look like… (Off topic, sorry)

8 Likes

I am celebrating this!

I had opened an issue to Cabal only a few days ago and I felt with my own heart that the attitudes have changed to better, so I see new hope.

Some issues were brought up above.

  1. What to do about v1 commands. Javier @jneira explains that some people like to install libraries to the top level environment. (User environment? Global environment? What is the official name of this entity?) This brings up a bunch of questions.

    • Who are these people and what are the actual stories? I can imagine such a state of mind, and it is plausible, but imagination is not a source of knowledge — only empiric evidence is. Plausible imagination is merely an inspiration for doing the research.

    • If we do not want people to install libraries to the top level environment, then why is there a top level environment in the first place? Can we let it go? Like, what if there were no top level environment at all?

    • I like to use ghci as a calculator as much as the other person. Consequently I also like to have some packages available by default and some extensions set. Writing this stuff into ~/.ghc/ghci.conf is dangerous because it is evaluated for every cabal repl in every package and conflicts crop up that are hard to debug. Installation of libraries into the top level environment is also clearly problematic. So, there is a use case that is poorly supported.

      How can I officially set up a top level Cabal package that I can then run ghci in from anywhere, including from the inside of other Cabal project directories?

  2. What to do about Stack.

    I was the one to bring this up previously, even at my own reputational and psychological expense. See open letter to Haskell Foundation discussed at Haskell Café and a discussion on Reddit. I meant it to speak about the shortcomings of Cabal — that I see being addressed even now — but it spilled over into a Cabal–Stack flame war. This being the Haskell community, the ensuing conversations were at least in part constructive, so we can gather some evidence as to what people think problems in this area are.

    Many people said they need Stack, but no one managed to name a single feature exclusive to Stack — rather, the problem is that things that are easy with Stack are hard to do with Cabal:

    • Cabal is unwieldy when it comes to managing GHC installations. (An external tool ghcup is needed.)
    • Stackage snapshots are hard to set up. (There is a hack but it is so convoluted hardly anyone would bother.)
    • Project management is yet obscure. (Since many people have not yet caught up with cabal.project and, for whatever reason, it is not widely advised.)

    This is what I make of the data, please point out if I missed something!

    I also briefly talked to some of the developers of Stack and I found that they are not maintaining it for fun. It is as easy to find features support for which is not being added and bugs that are not being worked on in Stack as it is in Cabal. That we, the Haskell community, do not have enough human resources, is the case. It is not merely some imaginary future progress that is at a question — both projects are already in technical debt.

    The costs are also being paid by us the people every day. See fresh example: project does not build — wrong build tool.

5 Likes

Wow, thank you @kindaro, eloquent and well-written :clap:

While I may differ slightly in my propositions, the “problems I have in mind” are definitely legit and a shared perspective. I really scratch my head when someone pushes back so intensely on those points, particularly on usability.

At least between stack/cabal, I also see it kinda silly to argue about unix-philosophy.

Here’s a random data point for what it’s worth: I gave haskell a shot before Stack, and I gave up solely due to cabal and the ux it provided. I could not understand how that ux was considered reasonable or usable. When Stack came about, I started learning Haskell. At least for me, stack provided a reasonable workflow and user experience that would allow me to focus on haskell and learning my way thru that (instead of fighting with my build tool). Stack isn’t perfect, but (at least for this idiot) it aims to be helpful and reasonable.

I have tried cabal a few times over the years since I picked up haskell in more earnest, mainly after the v2 commands came up, and again a few months ago. I couldn’t really tell that anything seriously improved/changed. I mean, I know there is new functionality, but the philosophy and hap-hazard organization is still the foundation. To this newb and the newbs I’ve worked with, the tool makes no sense, is frustrating to use, not discoverable, and provides little in the way of a holding hand thru the madness that is building software. While I love recommending Haskell, I don’t recommend cabal to them.

To that end, it seems stack has what cabal is missing (usability, support for stackage), while cabal has what stack is missing (a little more flexible about ghc). Probably some other differences too… so that is why I end up wondering what it might look like for the efforts to be combined in some form, and why I asked what the cabal team thought of those possibilities.

5 Likes

(in reference to people who like to use the global environment)

I am such a person. I have two entirely separate stories that support the top-level workflow:

  1. As a GHC developer, I often want to tinker with Haskell code. I have no project or real goal, other than to understand Haskell better. And I want to be able to just import whatever modules I want, without worrying about packages and updating a .cabal file.

  2. As a Haskell teacher, I often want to start a GHCi session to demonstrate a technique or datatype. And I want to be able to import whatever modules I want, without worrying about packages and updating a .cabal file. Sometimes a student asks a question, and so it all happens spontaneously – it would be very distracting to have to update my .cabal file just to be able to import a module already compiled on my system.

I know the harms that a global package store can cause. And I have tripped over incompatible bounds a few times. I deem the convenience of having a global store worth the problems I very occasionally encounter. To be clear: I agree with a project-based workflow for many, and I think that should be the primary use-case. But I have been frustrated for years at the difficulty of maintaining my global environment workflow.

8 Likes

Wouldn’t it help if you had (an easier?) way to create a temporary, throw-away, or otherwise isolated sandbox env that you could install whatever you wanted into? Or some easy way to “wipe-clear-reset” the “cache” in the “global env”, resetting it to the defaults or a previously known-working config?

Thank you Richard. This is what we need to move forward.

If you are open to a conversation, I should like to try and fit an imaginary improved Cabal to your stories.

But first we should gather the requirements!

  1. As a GHC developer … I want to be able to just import whatever modules I want, without worrying about packages and updating a .cabal file.
  2. As a Haskell teacher … I want to be able to import whatever modules I want, without worrying about packages and updating a .cabal file.

So you want to have an interactive session with a bunch of familiar modules. I am not sure if there is some difference you are not mentioning, in-between your two cases and also between them and my «calculator» case?

If truly there is a common story, then I imagine it might read as follows:

  1. Invoke ghci.
  2. Type import Data.Fancy.
  3. Type :set -XFancyTypes.
  4. Enjoy.

I can make this story even better with my imaginary improved Cabal: extensions can be set ahead of time, removing №3.

Imagine this:

  • ghci is actually cabal repl --project-file ~/.cabal/top-level.project lib:top-level.
  • cabal install --lib X is actually cabal magically write dependency X into top-level.cabal and resolve build plan rolling back if it fails --project-file ~/.cabal/top-level.project.

How cool is that ha?

P. S. In the light of the conversation linked below by Tom, I should mention that nothing prevents Cabal from addressing this concern:

Some of this is also, for me, philosophical: I don’t want anything between me and GHC. That is, I want to know exactly what flags are being passed to GHC and to be able to control those flags myself. A tool that installs libraries should do that, and then get out of the way.

Theoretically, you can get a cabal exec $SHELL even now. We only need to make it a well-supported, first class feature and voila.

I asked a similar question on haskell-cafe a couple of months ago and Richard was the only person who replied. I’m not sure if I should take that as an indicator that not many people actually value this style.

1 Like

This is what stack does. Just replace ~/.cabal/top-level.project with ~/.stack/global-project/stack.yaml.

2 Likes

Wow, thank you @kindaro, eloquent and well-written :clap:

Thank you o serpent of precious feathers. Your kind words really help.

Here’s a random data point for what it’s worth: I gave haskell a shot before Stack, and I gave up solely due to cabal and the ux it provided. … I have tried cabal a few times over the years since I picked up haskell in more earnest, mainly after the v2 commands came up, and again a few months ago. I couldn’t really tell that anything seriously improved/changed. I mean, I know there is new functionality, but the philosophy and hap-hazard organization is still the foundation. To this newb and the newbs I’ve worked with, the tool makes no sense, is frustrating to use, not discoverable, and provides little in the way of a holding hand thru the madness that is building software.

I sympathize with this. And I also went with Stack for a while. But the most straightforward way to make things better is to make things better, that is to say, improve Cabal rather than maintain a baroque wrapper. And I believe that with Emily on our side we can do that.

But we need actionable intelligence first. That would be a collection of tickets describing the issues you and your friends are having with Cabal, user experience and all. There is no one that can file these tickets but you. Once again, Emily being here I believe it is safe now, but you can also open issues in Tilapia — it is protected by the guardian spirit of a jaguar. Without such evidence as you may provide, improvement is impossible.

A next step would be to attach a tag «user experience» to those tickets and find someone to try and imagine what that improvement might look like.

1 Like

cabal-env also does something like that but it stores the constraints in the default package environment of GHC. It has been working nicely for me.

I like the global environment too, mostly to install a set of basic packages that I want to use many times like bytestring, text, vector, criterion, optics, then I never have to create a whole cabal project if I only want to use those packages.

One of my use cases is copying random code from the internet, pasting it into a .hs file and trying to compile it or load it into the repl. Maybe even writing a small benchmark around it.

3 Likes

We could link all the cabal issues with cabal v2-install --lib, users trying it usually want a non-project centric workflow, but we could do a search in the cabal issue tracker too.
In the fp discord server i’ve seen several users struggling with setting dependencies for ghc for exploratory or pedagogical purposes (like mentioned ones by @rae). Non project-centric workflows are usual in contexts where you try to help beginners with ghc, without introducing them in all the complexity of a stack/cabal project (cc @edmundnoble) .
Iirc xmonad scripting also needs to have dependencies in scope without a project (cc @liskin) .

stack somewhat fixes the issue having a global project configured in its global config dir. Not sure if cabal could do something alike, but it tries to be more explicit in general and maybe an implicit global project will not match its (actual?) design principles. As mentioned above @phadej cabal-env has been used and afaik succesfully as a replacement fot cabal v2-install --lib.

The ticket for the cabal install --lib replacement aka cabal env is this by the way: https://github.com/haskell/cabal/issues/6481

2 Likes

I strongly agree with this sentiment. I invoke GHC dozens of times each day, in lots of different directories. I really want to be able just call it, passing the flags that I decide.

I think of installing packages globally as like putting things in my global .ghci file – it just sets my global defaults. E.g. I don’t think anyone is advocating making ghci not load the Prelude (a current global default) unless you invoke it from cabal. That is, making GHC usable only via cabal.

This seems like a rather simple workflow to support. Is it problematic, really?

3 Likes

Switching from «use a sandbox, rebuild the whole world every time, get passive aggressive looks from Greta» to nix-style builds was paradisiac to me. Same with install --lib, saner defaults for init, etc.
I am happy to have witnessed cabal growing up.

2 Likes

I’m another user of cabal install --lib and package environments. For stuff like writing some quick example code to post somewhere, I don’t like to create full-blown packages, and prefer to work with ghci directly. It also feels snappier.

I tend to create local environments with cabal install --lib --package-env .. Partly because, on Windows, there was a bug (now solved) that put the global environments in a place GHC didn’t look for.

Admittedly, cabal install --lib is an ungainly command, becase the invocation without --lib does something which is very different.

I believe cabal env is the correct way forward, and eagerly await its inclusion into cabal-install. I don’t think the -v1 commands should keep being supported once cabal env arrives.

That said, some effort should be devoted to remind library authors to change pervasive obsolete documentation like

Install it in the usual way:

$ cabal install

which doesn’t work even now and is a source of grief for newcomers. Perhaps Hackage could display automatically generated and up-to-date installation instructions along package READMEs.

3 Likes

So, the summary so far is that many people like to use ghci with a global environment, and they still use Cabal to put packages into said environment. Therefore Cabal should support this use case — but it does not mean it should support it via v1 commands, right?

I am going to explain why I prefer to create temporary packages (cabal repl --build-depends … and cabal scripts), even though they are slow to launch.

  1. I want some language extensions and modules to be available in ghci immediately, but it opens a space for conflicts, as I mentioned above.
  2. I have no idea how to manage broken environments, and broken global environment is going to necessitate my removing of all caches and a few hours lost.
  3. I actually have no idea what an «environment» is in the first place and I am yet to see a beginner friendly «how to» guide.
  4. I once asked how to uninstall a library and was told there is no way.

The bottom line is that there are two ways to manage sets of packages and settings: environments and packages. This means twice the bugs and twice the learning curve. Solution? Officially support this use case in Cabal.

Is cabal env the thing? I am not sure. Can I configure an environment the same as I configure a package? Or do I need to learn a different configuration language? That would be unfortunate.

2 Likes

My three workflows:

  1. Build a collaborative project in exactly the same way that my collaborators do, every time, so that “works for me” is a distant memory, and so we can reuse build results.
  2. Build throwaway prototypes quickly, so I don’t have to wrangle a metadata file just to show off a quick idea
  3. Yolo some new packages and try to learn about them without “committing” to it.

How I satisfy these workflows:

  1. Cabal + Nix + Nixpkgs pins. I get precisely the same deps every time, and no rebuilding!
  2. NixOS + ghcWithPackages to build a Haskell Platform-lite in my system description.
  3. nix-shell -p 'haskellPackages.ghcWithPackages (p: [ p.fancy-package ])'

This will work for me for the forseeable future. All I can imagine doing is swapping out some of the implementation details. For instance, in my ideal world, cabal would be a unixy tool that calculates build deps which I would feed into the Nix furnace. That would make it pretty easy to migrate a project from the second or third workflow into the first workflow, should the opportunity arise.

2 Likes