A minor addition: I'd like to add a shortcut so you can write 
`Mix.install([:decimal])` instead of  `Mix.install([{:decimal, ">= 
0.0.0"}])`.

> The only downside of this approach compared to global dependencies is 
that each IEx session is a blank session - but that can be streamlined in 
the future.

Agreed. I didn't mention this in the proposal but here's a trick I've been 
using:

# ~/.iex.exs
unless Code.ensure_loaded?(Mix) do
  Mix.install([
    :decimal,
    :jason,
    :nimble_csv,
    {:requests, github: "wojtekmach/requests"}
  ])
end

This means however that when you start a session, you won't be able to call 
`Mix.install` again. In those cases I'd `iex --dot-iex ""` to ignore my 
global config.


czwartek, 21 stycznia 2021 o 12:05:18 UTC+1 José Valim napisał(a):

> I have discussed this with Wojtek and I am in favor of this proposal.
>
> Elixir was designed to support scripting but I constantly hear that the 
> lack of some quality of life features, such as trapping exits, limited IO 
> handling, lack of support for dependencies, etc make it so even advanced 
> Elixir developers don't end-up using Elixir for regular single-file scripts.
>
> I have never been a fan of global dependencies. Between global 
> dependencies (not easily reproducible and with implicit dependencies) and 
> Mix projects (fully reproducible with explicit dependencies), this sounds 
> like a reasonable compromise (explicit dependencies reproducible within 
> requirements). The only downside of this approach compared to global 
> dependencies is that each IEx session is a blank session - but that can be 
> streamlined in the future.
>
> Note the goal here is not to replace escripts either. Escripts have the 
> full-backing of a project, with dependencies, multiple source files and 
> tests. If it is anything beyond experimentation or more than a couple dozen 
> lines, then you do want a complete project.
>
> TL;DR: +1
>
> On Thu, Jan 21, 2021 at 11:40 AM [email protected] <
> [email protected]> wrote:
>
>> 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
>>  
>> <https://groups.google.com/d/msgid/elixir-lang-core/ed320491-005c-4414-b1a9-5ca0e540bd3dn%40googlegroups.com?utm_medium=email&utm_source=footer>
>> .
>>
>

-- 
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/77c21ba1-788c-488c-be8e-67597dc22c71n%40googlegroups.com.

Reply via email to