Skip to content

Instantly share code, notes, and snippets.

@aaronc
Last active December 17, 2015 04:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save aaronc/164c5aab37982ca3e372 to your computer and use it in GitHub Desktop.
Save aaronc/164c5aab37982ca3e372 to your computer and use it in GitHub Desktop.
Proposal for Idris Package Support to Prevent "Dependency Hell"

Proposal for Idris Package Support to Prevent "Dependency Hell"

I know there has been some discussion around what type of package manager to use for Idris. I know some people have proposed Nix and I've started checking it out myself. This proposal is really aimed just at low-level support that would help any package manager (including Nix) prevent the soul-sucking, time waster that is dependency hell.

It seems that most languages don't address this until it is too late and then need extraordinary community efforts to deal with it (ex. Haskell with Cabal sandboxes and Stack or Java with Project Jigsaw). Only one platform I know of (NodeJS with NPM) got it right from the start by allowing a nested dependency graph. With some careful planning and a few pieces of language-level support I think Idris can do this too.

I think what is most essential in preventing dependency hell is being able to reference two different dependencies that declare a module with the same name. I've done a check with Idris in it's current state and it clearly does not handle this scenario well. What I'm proposing would make it possible for a single build to include (directly or transitively) multiple versions of the same dependency or dependencies which have module naming conflicts. It will also allow for users to disambiguate modules with naming conflicts in source code and to override transitive dependencies to help get the build graph exactly the way they want it for their project. I think that making these things possible will make a huge difference for users of the language in the long run.

Package IDs and Package Aliases

I think the above can be accomplished by introducing the concepts of Package ID and Package Alias and making a few small changes to the Idris language, Idris TT and the idris command-line tool to support them. Package ID and Package Alias are defined below:

Package ID: a string identifier for a package that must be unique within the set of all packages in a given build graph (i.e. all the direct and transitive dependencies of the package being built - a package itself is implied to be a set of modules which are uniquely named within the package). Package ID's themselves will never be used within source code.

Package Alias: a short alphanumeric identifier (similar to a module alias defined with as) to be used within source code that is scoped to a single package to refer to a dependency without actually naming its full Package ID.

Basically Package IDs are globally unique within a build (and could be something descriptive like "my-package-0.1.0" or possibly something like a Nix hash) and Package Aliases are short string identifiers (ex. "myPackage") to be used within source code that are scoped only to the package currently being built. Package Aliases can be assigned to Package IDs on the command line when building a single package and would be used for disambiguating modules with the same name. Package IDs would persist into .ibc files whereas Package Aliases would disappear once type checking is complete. ex. If package A-0.1 references package B-0.2 with alias B, any reference to alias B in source code gets translated to B-0.2 in the resulting .ibc files.

Changes to the Idris Language

The import statement would take an additional from parameter that takes a package alias as an argument to be used for disambiguating a module that is not uniquely named within the build graph. Ex:

import A from myPackage1
import B from myPackage1 as B1
import B from myPackage2 as B2

Changes to Idris TT

The NS constructor of Name would take an additional Text parameter for the Package ID. This will allow for the same namespace to be defined in multiple packages without conflict.

Changes to idris command line tool

The following command line arguments will be added/updated:

  • --id <package-id> which assigns a Package ID as described above to this package
  • -p<package-dir>[,<package-alias>] where package-dir is the absolute or relative (to the Idris lib dir) path to a dir containing the pre-built .ibc files for a package dependency - these files should already have the package-id (set via --id) compiled in. package-dir does not have to (but probably should) be similar to the package-id. package-alias is as described above and is only required when source code references a given package alias.
  • --meta <package-meta> takes a string of package metadata to be used primarily for documentation (probably key values pairs like name=my-package,version=0.1.0,group=...,dependencies=...,build-params=...,author=...,url=...). This would free Package ID's to be something globally unique like a hash while supporting rich generated and REPL documentation.

What could build tools do with this approach?

This approach would free build tools to implement a dependency graph as the programmer chooses. Packages could define preferred versions of dependencies while allowing users to override transitive dependencies with different versions or even totally different packages. A package manager may also allow a user to choose a flat dependency graph where possible while only using a nested graph where it's necessary to "get out of dependency hell". Because source code will only use package aliases for module disambiguation, source code itself is never tightly coupled to specific packages.

I'm not really sure how complicated this would be to implement, but "dependency hell" is a huge frustration for both developers and language communities and it would be nice to see such a promising language as Idris implementing this from early-on. I know there is ongoing discussion of a new module system so maybe this sort of consideration could be addressed while that is getting done. I would think that sophisticated package management would go hand-in-hand with a sophisticated module system.

Anyway, I look forward to discussion regarding this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment