4 ms·
I was wondering if someone could explain something to me. I understand the issues involving inconsistent environments, but bad constraints don't really seem lik
by SuperStache 12y ago
I was wondering if someone could explain something to me. I understand the issues involving inconsistent environments, but bad constraints don't really seem like a particularly challenging issue to me.
If you have libraries A and B which each require mutually exclusive versions of library C, what is stopping the compiler from adding both versions of library C to the compiled code for A and B to call separately?
Obviously this would result in larger binaries and should generate a build/install warning, but it seems like this would solve the overwhelming majority of Cabal's dependency resolution issues.
There's clearly something I'm missing since this has been an outstanding issue in Cabal for quite some time. Would someone with a better understanding of GHC/Cabal's compilation/linking/installation steps mind shedding some light on this?
- wpietri 12y agoI think that would only work if neither A nor B exposes anything about C. I'm not a Haskell user, but certainly in Scala and Ruby there are plenty of libraries where library consumers see objects from underlying libraries. Suppose C is a JSON library, for example. In my code I fetch a JSON object from A, with library version C1. What happens when I pass that object to library B, which uses C2? Is that an immediate type violation because C1 and C2 are treated as different types? Do you live with runtime failures when, say, B calls a C2 method not in C1? Do you you try to create some sort of magic object conversion and hope that the data isn't too different? Or do you try to require all libraries to describe how to convert data from every version to every other version? Even if the two libraries never interacted and data could be proven never to flow between them, there's a real question as to what version of the library is available from the main code. Despite my concerns, I suspect that you could make this mostly work if you were cavalier about possible runtime errors, because actual conflicts would be rare. But from what I understand of the Haskell community, they're not big on "cross our fingers and hope it works at runtime" approaches.
- munificent 12y agoI maintain the package manager for the Dart language. This question comes up all of the time. The problem is that these libraries may interact at runtime: * A gets a value from its version of C. * It passes that to your app. * Your app gives it to B. * B gives it to its incompatible version of C. Haskell may handle this scenario differently because of its type system, but in Dart, this would cause lots of user problems.
- tel 12y agoThat's exactly what can happen. Cabal endeavors to prevent multiple versions of a package from being installed simultaneously, but as this post mentioned Cabal does not maintain global consistency so if you do multiple independent installs in the same database then you can wind up with this problem. In particular this is, for whatever reason, a frequently occurring problem with the `bytestring` library. There are a lot of SO questions related to figuring out why the compiler is rejecting the use of a ByteString type even though it appears it should work... but that's because the compiler error is eliding the package version difference.
- seagreen 12y agoAnyone know if there's a formal name for this situation/problem? Thanks for the clear explanation BTW.
- tel 12y agoYou probably would have good vocabulary for this in the ML family languages. You're essentially talking about existential type mismatching—a core component of how modules work in ML family languages. It's just hard to read that into Haskell since "modules" are not as well represented in-language and exist somewhere between Haskell-the-language and Cabal-the-package-manager/ecosystem.
- munificent 12y agoI don't think there's a well-known name for it. I'd call it something like a "non-encapsulated dependency".
- nawitus 12y agoHmm, npm with Node.js allows that to happen. I don't recall that causing any problems, though. The "solution" seems to be that B is tested with both A and C, and when you're developing B, you know what kind of values you get from A, and you know what kind of values C accepts.
- munificent 12y ago