I originally opened a github issue on hex, but it was pointed out (correctly) that this is actually a `mix` proposal not a `hex` proposal.
https://github.com/hexpm/hex/issues/899Original Proposal Text:
# The problem
Ash Framework comes with a dependency called [picosat_elixir](
https://github.com/bitwalker/picosat_elixir), which uses a NIF. This causes problems for some users, so I've implemented a (slower) alternative natively in Elixir using [csp](
https://github.com/Lakret/csp). However, I don't really want most people using the `csp` dependency unless they encounter problems with the `picosat_elixir` dependency. So I'm looking for behavior that is essentially "one of these dependencies needs to be specified, but if none of them are, use `picosat_elixir` as the default". This seems like it could be useful for other use cases, like `json_formatter` or `http_library`, allowing for a more seamless initial installation process, and automatically choosing the recommended library.
# The temporary hacky workaround
I haven't actually released this yet, but in Ash we'd have:
```elixir
{:picosat_elixir, "~> 0.1.5"},
{:csp, "~> 0.1.0", optional: true},
```
And then there is a troubleshooting guide that instructs people who really can't get picosat_elixir set up to add the following to their dependencies:
```elixir
{:picosat_elixir, override: true, only: []},
{:csp, "~> 0.1.0"},
```
Less than ideal :D
# The proposal: Optional Dependency Groups
This is just one potential way it could be implemented:
```elixir
defp deps do
{:picosat_elixir, "~> 0.1.5", group_default: true, group: "Sat Solver"},
{:csp, "~> 0.1.0", group: "Sat Solver"}
end
```
We could also use `priority`, e.g `group_priority: 1`, `group_priority: 2`, and then choose the highest priority dependency that has no conflicts.
And then of course if one of the dependencies is explicitly configured in the user's `deps` then we just use that one no matter what.
The benefits of a strategy like this:
Right now, the typical way of switching on dependencies is something like:
```elixir
if Code.ensure_loaded?(ModuleInDependency) do
...
end
```
That is theoretically brittle depending on what module you choose. Some other dependency they use could also (very unlikely, but possible) define a module of the same name. But since mix has the group names, we could do something like this:
```elixir
if Mix.group_choice(:ash, "Sat Solver") == :picosat_elixir do
....
end
```
I'm sure there are probably a few aspects of this I haven't considered, but it seems like it could be useful for others as well.
We could also display the group something was installed for/the reason of it when installing, e.g
```elixir
csp 0.1.0 (Group: "Sat Solver")
```
Images of the comments attached: