A dialogue

NeverCast

o/ What’s the difference between stack and cabal, and what are they? Dependency management or something?

Is it a case of one or the other?

electronnoble

Oh boy okay

So firstly to answer your last question

One can make their project buildable with both stack and cabal

Stack and cabal are build tools, and Haskell package managers

However there is considerable overlap because stack uses the libraries that make up cabal

Cabal projects are described by .cabal files, and stack projects are also (with a caveat) described with .cabal files, plus an additional stack.yaml file

This does not however mean that any old stack project with a cabal file will successfully build with cabal!

And many stack projects use another format, package.yaml, which a tool called hpack converts into a cabal file on the fly (or something like that, not sure about the internals)

But even if you do have a cabal file, building with cabal may not work because there are two main features separating stack and cabal

Firstly stack will manage GHC installations, so if a project needs a version of GHC which you don’t have, stack will download and install and use it, whereas cabal will error out unless you tell it where your alternate GHC install is

Secondly, stack picks which version of package you want differently from cabal (a huge point)

NeverCast

stack version locks the entire repo, right?

electronnoble

Not exactly

Kind of

Using cabal freeze files you can version lock your repos

Stack does more than that

Here’s how an example cabal file does dependency versioning

build-depends: base >= 4.11 && < 4.13

, hailgun ^>= 0.4.2

, beam-core ^>= 0.8.0.0

, beam-sqlite ^>= 0.4.0.0

First one is an ordinary version range, p ^>= x means "this project works with any version of p above x before the next major version"

And cabal figures out automatically which versions of packages work and selects the newest ones for you

(except if you have a freeze file which locks your project versions down for reproducible builds)

Here’s how it looks in a cabal file for a stack project

build-depends: base

, hailgun

, beam-core

, beam-sqlite

Note that the version ranges just don’t exist

Because in your stack.yaml file you have an entry:

Like this:

resolver: lts-13.23

Which locks all of your package versions to be equal to those in the “lts-13.23” stackage snapshot

And for every package which isn’t in stackage, you have an entry

extra-deps: beam-core-0.8.0.0

Which says the exact version you want

That’s basically it

That’s also why cabal files for stack projects can be broken for cabal: if you have no version bounds, cabal has no way to figure out what package versions you want

NeverCast

I have project a It depends on b and c , b also depends on c I assume Cabal will try to find the newest version of c that matches the version requirements of both a and b and lift that to the top. I am not assuming that Cabal builds with multiple versions of the same package

electronnoble

Yep

NeverCast

if b has a loose dependency on c such that it may bump a major version, or if the developer of c does not respect semver. a may cause c to be updated to a point where b does not work. Alternatively b may cause c to be held to a lower version than what a is expecting (because there was a bug fix in a minor version which b does not depend on) Now b will build with old c but a will fail. These are the issues with Cabal

electronnoble

semver is not a thing in Haskell except on stackage

We have the PVP

You’re saying a may require a version of c which b does not work with?

NeverCast

With stackage, you may not have bleeding edge packages, but they should all be compatible with each other?

> You’re saying a may require a version of c which b does not work with?

Yes I did say that. I assumed this can happen in Cabal but would not happen in Stack

electronnoble

If b was not updated to work with the new c

It won’t be on the new stackage resolver

NeverCast

Can a package be in Resolver 1, and gone in Resolver >1 ?

electronnoble

Oh yes

If c updates, and b doesn't work with it anymore

b is removed from stackage

Until that changes

So the thing to my mind which stackage actually does

Is it runs the tests of all of the versions on a resolver at once

NeverCast

Stack seems reliable for automated builds and production But Cabal seems nicer for development. With that said, if you wanted to move from Cabal to Stack that could be problematic, finding a resolver

electronnoble

Keep in mind also, lots of packages can end up in extra-deps , which gets you into a worse situation for versioning than in cabal!

Because you don’t even have version ranges anymore

If I wanted to put cabal in prod though I would absolutely use a cabal freeze file, no question

Yeah moving from cabal to stack could break a bunch of packages, so typically you’d just add a stack.yaml file, and keep the cabal version bounds you had

Which loses you one benefit of stack, which is that everyone updates at once, but you keep the benefit of cabal’s version ranges for downstream cabal users

Also GHC management is a particular sticking point for some people, especially windows users

NeverCast

Do windows users not get automated updates, or they do and that’s nice?

electronnoble

I don’t really know how windows users manage GHC

NeverCast

Is there an encouraged preference to favour Stack or Cabal over the other, when it comes down to developing a Package vs developing an Application ?

electronnoble

It really depends who you ask

People who recommend stack generally recommend it everywhere, and vice versa for cabal

(I may just be hearing the vocal ones)

Personally I encourage cabal in all cases but you know, if you want stack users to use your library, why not add a stack.yaml

NeverCast

Makes sense.