Today, the only way to use dependencies in Elixir is by first adding them
to the current Mix project or installing them as archives. This makes
Elixir less than ideal for simple tasks where you'd usually use a scripting
language, e.g. download a JSON file, parse it, extract some data. This is
also adding pressure for a more "batteries-included" approach in the stdlib
to make these simple tasks more convenient to accomplish and require
neither creating a Mix project nor installing dependencies.
I'd like to propose adding a `Mix.install` function that will download,
compile, and load given dependencies into the VM.
Here's how we could use it from an IEx session:
$ iex
iex> Decimal.new(42)
** (UndefinedFunctionError) function Decimal.new/1 is undefined (module
Decimal is not available)
Decimal.new(42)
iex> Mix.install([{:decimal, "~> 2.0"}])
:ok
iex> Decimal.new(42)
#Decimal<42>
Or from a script:
$ cat run.exs
Mix.install([
{:decimal, "~> 2.0"},
{:jason, "~> 1.0"}
])
IO.puts Jason.encode!(Decimal.new(42))
$ elixir run.exs
"42"
You need to call `Mix.install` in your VM and explicitly list all your
dependencies. And if you start a new VM, you'd have to call `Mix.install`
again.
Under the hood, the `Mix.install` starts Mix and creates a temporary Mix
project to install and load the dependencies and unloads the temporary
project when it's done. For simplicity, the initial implementation allows
you to only call this function outside of a Mix project and you can only
call it once in a given VM.
The temporary project is preserved across runs so if you start another VM
and call `Mix.install` with the same set of dependencies, they'll be loaded
right away without needing to download or compile them. Each set of
dependencies will have it's own temporary directory, roughly:
`/tmp/mix_installs/<md5_of_deps>`.
The location and the layout of the temporary project is considered an
implementation detail that users shouldn't depend on.
The fact that the resulting `mix.lock` file is hidden from the users
presents challenges around reproducibility and updating deps. If you pin
your deps to specific versions, a call to `Mix.install` will give
consistent results, however if you use version requirements like `~> 1.0`,
it may give different results depending on what the deps resolve to at at
given time. Similarly, if there's a new version of a package that satisfies
a given version requirement, `Mix.install` won't automatically install it
as it already cached the dependency. For this, you'll be able to pass a
`force: true` flag to bypass the cache and install & compile from scratch
for a given set of dependencies. This will also help if your install
somehow got into an inconsistent state.
### Reproducibility
Another way of quickly installing and using dependencies is via workspaces,
you'd install and automatically load dependencies within a given workspace.
That brings questions about reproducibility.
Imagine you write a piece of Elixir code that uses dependencies and share
it with people, how reproducible is it?
- using Mix project, the dependencies are fully reproducible given the Mix
project maintains a `mix.lock` file
- using `Mix.install`, the dependencies are reproducible within the
specified version requirements
- using global state like workspaces, the dependencies are not
reproducible. If you ask a user to run your script, you need to tell them
what dependencies they need to install
Between global dependencies having very weak reproducibility and Mix
projects being fully reproducible, `Mix.install` is a compromise where you
can reasonably reproduce things within a list of requirements.
### Further reading
Thanks to https://hex.pm/packages/teex authors for exploring some of these
ideas!
Also see https://github.com/wojtekmach/playground for an earlier
proof-of-concept and
https://github.com/elixir-lang/elixir/compare/master...wojtekmach:wm-mix-install
for a work-in-progress implementation.
--
You received this message because you are subscribed to the Google Groups
"elixir-lang-core" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To view this discussion on the web visit
https://groups.google.com/d/msgid/elixir-lang-core/ed320491-005c-4414-b1a9-5ca0e540bd3dn%40googlegroups.com.