[Proposal] Enhancements in the API for optional dependencies

180 views
Skip to first unread message

Michal Śledź

unread,
Mar 7, 2023, 6:40:51 AM3/7/23
to elixir-lang-core
Currently, using optional dependencies is quite inconvenient and error prone:

1. A lot of modules have to use if Code.ensure_loaded statements introducing additional nesting
2. Users of a library with optional dependencies have to include all optional dependencies in their mix.exs
3. Users might include bad varsions of optional dependencies

My proposal is to enhance API for optional dependencies basing on the API provided by Cargo in Rust.

The main idea is that the user of a library with optional dependencies specify which "features" it is willing to have. For example, in membrane_rtc_engine library, which allows you to exchange audio/video using different multimedia protocols, we have a lot of optional dependencies depending on what protocol the user is willing to use. When the user wants to receive media via webrtc and convert it to the HLS to broadcast it to the broader audience it has to include all of those dependencies

   # Optional deps for HLS endpoint
   {:membrane_aac_plugin, "~> 0.13.0", optional: true},
   {:membrane_opus_plugin, "~> 0.16.0", optional: true},
   {:membrane_aac_fdk_plugin, "~> 0.14.0", optional: true},
   {:membrane_generator_plugin, "~> 0.8.0", optional: true},
   {:membrane_realtimer_plugin, "~> 0.6.0", optional: true},
   {:membrane_audio_mix_plugin, "~> 0.12.0", optional: true},
   {:membrane_raw_audio_format, "~> 0.10.0", optional: true},
   {:membrane_h264_ffmpeg_plugin, "~> 0.25.2", optional: true},
   {:membrane_audio_filler_plugin, "~> 0.1.0", optional: true},
   {:membrane_video_compositor_plugin, "~> 0.2.1", optional: true},
   {:membrane_http_adaptive_stream_plugin, "~> 0.11.0", optional: true},

Instead of this, I would love to say to the user, hi if you want to use HLS just specify it in the feature list. For example:

{:membrane_rtc_engine, "~> 0.10.0", features: [:hls]}

It would also be nice to somehow get rid of "if Code.ensure_loaded" statements. I am not sure how yet but Rust do this that way

// This conditionally includes a module which implements WEBP support. #[cfg(feature = "webp")] pub mod webp;

What comes to my mind is that in mix.exs we can specify "features", their dependencies and a list of modules. When someone asks for the feature, those dependencies are autmatically downloaded and listed modules are compiled. 

The final proposal is:

# library side
# mix.exs

features: [
  hls: [
    dependencies: [],
    modules: []
  ]
]

# user side
# mix.exs

{:membrane_rtc_engine, "~> 0.10.0", features: [:hls]}

I would love to help in implementing those features if you decide they are valuable

Rust reference:
https://doc.rust-lang.org/cargo/reference/features.html#features
 

José Valim

unread,
Mar 7, 2023, 8:45:03 AM3/7/23
to elixir-l...@googlegroups.com
Hi Michał,

Thanks for the proposal. Your initial description makes me think there may exist bugs which we would need to investigate first.

2. Users of a library with optional dependencies have to include all optional dependencies in their mix.exs

This should not be required. You only need to include the dependencies that you need, which would be equivalent to opting into a feature in Rust.

3. Users might include bad varsions of optional dependencies

This should not be possible. The requirement has to match for optional dependencies.

If the above is not true, please provide more context.

---

Other than that, you should be able to provide this functionality using config/config.exs files and the Application.compile_env/2. In fact, I think introducing another mechanism to configure libraries could end-up adding more confusion, especially given how configs changed (and also improved) throughout the years.



--
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 elixir-lang-co...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-core/8385965e-799d-4cea-bcd5-151d9fee6914n%40googlegroups.com.

Michal Śledź

unread,
Mar 7, 2023, 10:17:06 AM3/7/23
to elixir-lang-core
2. Users of a library with optional dependencies have to include all optional dependencies in their mix.exs
I meant that to enable one feature, user has to include a lot of optional dependencies, at least in our case.


3. Users might include bad varsions of optional dependencies
Here, I meant that user has to exactly know dependency version that has to be included. In our case, when there is a lot of optional dependencies, it starts getting annoying to keep them up to date in the docs. 


Other than that, you should be able to provide this functionality using config/config.exs files and the Application.compile_env/2.
But I cannot manipulate which deps should be downloaded and compiled using Application.compile_env, can I? I mean, user still has to include all needed dependencies and know their correct versions. I also thought that configuring libraries via Application environment is discouraged, according to https://hexdocs.pm/elixir/library-guidelines.html#avoid-application-configuration

We very often depend on native libraries written in C like ffmpeg. When it's possible, we make those components optional, so that user is not forced to install uneeded native libraries on their system. 

I feel like at the moment user has to be aware of which optional deps are needed to get the desired feature. What I would like to have is to focus on the feature itself, leaving deps and their versions to library maintainers.



 

José Valim

unread,
Mar 7, 2023, 10:34:50 AM3/7/23
to elixir-l...@googlegroups.com
I understand better now. To make the issue concise, you would like to programmatically include optional dependencies. Today everything is based on the dependency name itself but you would like to have an abstraction layer for controlling it.

I think the biggest concern with implementing this feature is that it needs to be part of Hex itself. So the first discussion is if and how to extend the Hex registry to incorporate this metadata, which needs to happen in Hex first.

> I also thought that configuring libraries via Application environment is discouraged, according to https://hexdocs.pm/elixir/library-guidelines.html#avoid-application-configuration

Right. Application configuration has many downsides, exactly because it is global. The feature mechanism is also global, regardless if we put it on mix.exs or on the configuration environment. Rust also hints it is configuration (the conditional is called cfg):
#[cfg(feature = "webp")]
pub mod webp;

In this case, as long as the feature checks are only inclusive, it should be fine. But you can also think if a library named A assumes that dependency C is compiled without some flag, and library B assumes C is compiled with said flag, you will end up with conflicting behaviour.

---

One potential workaround that you have is to define dependencies to work as flags. Let's say you have a realtime feature that requires 3 dependencies, you can define an optional "membrane_realtime_feature"  package that, once included, signals the existance of a feature and also all of its dependencies. Alghouth it is most likely not a good idea to abuse dependencies in this way.

Michal Śledź

unread,
Mar 7, 2023, 11:06:27 AM3/7/23
to elixir-lang-core
> I understand better now. To make the issue concise, you would like to programmatically include optional dependencies. Today everything is based on the dependency name itself but you would like to have an abstraction layer for controlling it.

Yes, exactly! 


> One potential workaround that you have is to define dependencies to work as flags. Let's say you have a realtime feature that requires 3 dependencies, you can define an optional "membrane_realtime_feature"  package that, once included, signals the existance of a feature and also all of its dependencies. Alghouth it is most likely not a good idea to abuse dependencies in this way.

That's what we were thinking about too. In general, we know in the compile time which features we are going to need. At the end, user has to plug specific endpoints to the Engine on its own. For example:

{:ok, pid} = Membrane.RTC.Engine.start_link() 
Engine.add_endpoint(pid, %HLS{})
Engine.add_endpoint(pid, %WebRTC{})
Engine.add_endpoint(pid, %VideoRecorder{})
etc.

so in general, we could exctract each endpoint (WebRTC, HLS, Recorder) into a separate package and I belive this is a pretty elegant solution.

We would end up with:

{:membrane_rtc_engine, ...}
{:membrane_rtc_engine_webrtc, ..}
{:membrane_rtc_engine_hls, ...}
{:membrane_rtc_engine_recorder, ...}

However, allowing user to do 

{:membrane_rtc_engine, "~> 0.10.0", features: [:webrtc, :hls, :recorder]} 

looks even more attractive to me, and is easier to document as we can list all of supported features in the membrane_rtc_engine docs. Also, user doesn't have to think about versions as it includes only one dependency so it won't try to plug webrtc endpoint that is incompatible with engine.

Regarding:

> I think the biggest concern with implementing this feature is that it needs to be part of Hex itself. So the first discussion is if and how to extend the Hex registry to incorporate this metadata, which needs to happen in Hex first.

and


> In this case, as long as the feature checks are only inclusive, it should be fine. But you can also think if a library named A assumes that dependency C is compiled without some flag, and library B assumes C is compiled with said flag, you will end up with conflicting behaviour.

I don't have answers to those questions but I am willing to investigate them and propose more detailed analysis on how we could implement the whole concept assuming it sounds valid to you. 

José Valim

unread,
Mar 7, 2023, 12:00:05 PM3/7/23
to elixir-l...@googlegroups.com
> Also, user doesn't have to think about versions as it includes only one dependency so it won't try to plug webrtc endpoint that is incompatible with engine.

FWIW, this can be easily addressed by recommending users to add {:membrane_plugin, ">= 0.0.0"}, since membrane itself will already restrict it to a supported version.

At the end of the day, if the goal is replacing 3 lines:

{:membrane_rtc_engine_webrtc, ..}
{:membrane_rtc_engine_hls, ...}
{:membrane_rtc_engine_recorder, ...}

with:


{:membrane_rtc_engine, "~> 0.10.0", features: [:webrtc, :hls, :recorder]}

I have to say this is likely not worth it, given the amount of work implementing and maintaining this feature would entail in the long term.

I understand why Rust has this feature: compile-time and artefacts are much larger there. Plus the fact they can't metaprogram at the file level like us means they need explicit configuration for this. So before moving on, I think you need to send a more structured proposal, with the problem this is going to address, code snippets before and after, and so on. As mentioned above, this is a complex feature, so the benefits need to be really well justified over what can already be achieved today.


Michal Śledź

unread,
Mar 7, 2023, 12:22:07 PM3/7/23
to elixir-lang-core
I see, thanks! Will think/investigate this more and return when having more detailed proposal and justification

Aleksei Matiushkin

unread,
Apr 6, 2023, 1:09:29 AM4/6/23
to elixir-lang-core
I have encountered the very same issue and I think it might be half-supported without the necessity to incorporate anything in `hex`.

`Mix.Project.deps/1` callback already accepts `:system_env` configuration parameter per dependency, what if we also allow `:config` which would be merged into a dependency config during its compilation? That way we might rather simplify the dependency tree configuration at least when several dependencies came from the same provider, without the necessity to touch `hex` at all.

Consider A library optionally depending on B and C, whereas B also optionally depends on C. Then A might be included as `{:a, "~> …", config: [b: true, sigils: false]}` and then A would know at the compilation stage it should “flag C as used, and flag B as used without C, (and make sigil macros available.)”

It still does not help much to get proper dependencies from `hex` but at least it makes it possible to decrease the amount of boilerplate needed to make libs cooperate cohesively.

—AM

Yordis Prieto

unread,
May 8, 2023, 2:50:52 PM5/8/23
to elixir-lang-core
Do you think the features should be enabled according to the environment as well?

```
{:membrane_rtc_engine, "~> 0.10.0", features: [testing_support: [:test]]}
```

Allowing people to ship non-prod code (whatever that means to you) as part of the library but remove outside testing in this case

Michal Śledź

unread,
May 8, 2023, 3:36:10 PM5/8/23
to elixir-l...@googlegroups.com
That's a good question

Yordis Prieto

unread,
May 9, 2023, 1:27:34 PM5/9/23
to elixir-lang-core
Lately, personally speaking, the need for shipping a lot of testing-supporting functionalities is increasing; thus far, most popular packages in the ecosystem have some functionalities that are meant to be used only for testing (Plug, Broadway, Oban, ...).

It is not about dependency issues, but still, fixing one thing could help to fix something else that I find a pain point lately.

I have opt-in in to use `Mix.env() == :test` (I know some people don't like this strategy and they like to introduce some App config, but that is another topic). There is another thread about this topic.

In another situation, packages like Ueberauth/Tesla (I am one of the core maintainers of the org) are painful to maintain if you go for packages-per-strategy, but, on the flip-side, you must compile all strategies if you only have one package even though you want 2 or 3 strategies. Not a big deal to ship extra code, but still, I instead not ship things I don't want, and when other people in the ecosystem come, we have better answers to them, IMO.

Rust's idea is quite lovely as a library author.

Yordis Prieto

unread,
May 13, 2023, 2:57:20 PM5/13/23
to elixir-lang-core
Another situation I encountered maintains a popular Stripe package related to the "features" thing.

The package doesn't include Jason.Encoder for the built-in objects, which we could include, but some people may want to opt-in to their encoding for Jason.
It happened to me, but the opposite happened in Commanded Land, and the author suggested an "alternative" https://github.com/commanded/commanded/issues/504, but honestly, I wish we had better answers for it. From his perspective, I agreed with his take, but I still wanted more control over my app. I had to opt-in to completely replace the component because of it.

So the `Application.ensure_feature(:commanded, :jason_encoder)` function or something like that could be cool (just making a point, I don't care too much about the function name). Similar to compile_env.
I know people proposed that everyone invent their own "feature flagging," because nothing prevents you from achieving it today, but this is where I hard disagree. I prefer if the Elixir proposes something standard rather than figuring out every package out intent. I rather don't deal with the cognitive load, the having to figure out every single config, or not being able to build tools around it or make assumptions.

José Valim

unread,
May 13, 2023, 3:02:04 PM5/13/23
to elixir-l...@googlegroups.com
The behavior you describe could be fully achieved with config today. You could for example ask commanded to not define impl for Any, because you will.

My understanding is that the feature requested here is not really about conditional compilation, because that’s all possible today, but rather about conditional management of dependencies.

Michał Śledź

unread,
May 13, 2023, 3:53:43 PM5/13/23
to elixir-l...@googlegroups.com
Yeah. I also wonder about native dependencies. In Membrane, we have a lot of packages that use some C library under the hood but only in a couple of modules.

E.g. we have the package for h264 codec that ships with encoder, decoder and parser. Encoder and decoder use ffmpeg C libs, while parser is implemented in pure Elixir. 

With features, we could manipulate with compilation process so that if you don't need encoder and decoder, they won't be compiled and you don't have to install ffmpeg c libs.

You would do 

{:h264, "0.0.0", features: [:encoder, :decoder]}

or

{:h264, "0.0.0", features: [:native]}

Currently, we have to split native packages from pure elixir packages.

Yordis Prieto

unread,
May 14, 2023, 1:11:31 AM5/14/23
to elixir-lang-core
> You could for example ask commanded to not define impl for Any, because you will.
I did :) But told me to do an alternative which, at that point, I didn't care about enough.


>  but rather about conditional management of dependencies.

I get that. I am coming from a different perspective than yours that would help manage such dependencies based on how people deal with the dependencies today, such as using Code.ensure_loaded; and **try** to tackle the problem with a more "robust" idea.


> The behavior you describe could be fully achieved with config today.

As I said, I fully understand that it is possible today. Still, I disagree that every library author should invent their way, and the entire ecosystem must learn. That is a brutal, error-prone, and sub-optimal experience, IMO.

Build tools around it like ExDoc, Hex, or many other integrations by having the metadata in the mix.exs. Ergonomics matter, and I come from the perspective of the entire ecosystem impact, not just the technical aspect of achieving it today.

It is hard to disagree with the stand "it is possible today," but that doesn't help much the existing pain, and it feels suboptimal to me.

> Currently, we have to split native packages from pure elixir packages.

It is not the first time the conversation has happened.

For what it is worth, the Rust team focused on the fact that these situations will happen, and it is a fantastic addon to have from the get-go in an ecosystem. Maybe it is worth considering.

We could take it to the next level and have a fantastic ExDoc experience around it. Library authors would love it since it could help with the management of the libraries, and the users would love it too since they don't have to compile everything or be able to opt-in to alpha features and whatnot. Which is what my mind is thinking of. Like, taking the whole Deps Manamanget, Conditional Compilation, and Ecosystem to the next level 😎 Nothing is more excellent than ExDoc helping people thru rock-solid docs that are familiar across packages/ecosystems 😎

I trust you will figure it out. All I ask is a bit of curiosity.

José Valim

unread,
May 14, 2023, 2:47:44 AM5/14/23
to elixir-l...@googlegroups.com
> I get that. I am coming from a different perspective than yours that would help manage such dependencies based on how people deal with the dependencies today, such as using Code.ensure_loaded; and **try** to tackle the problem with a more "robust" idea.

Here is the issue: the proposal has not elaborated on how those problems will be tackled (outside of dependency management). 

Application.ensure_feature would most likely be a wrapper around config. So if you believe this approach can alleviate conditional compilation issues, it needs to be shown exactly how. I am afraid adding a new function won’t be enough (or at least I can’t see how it would).

In other words, I can see how features help dependency management. But not compilation. For the latter, we need a more concrete proposal with code examples, APIs, and more. And don’t ask us to figure it out, if you strongly believe in the idea and see its potential, then please carry it forward to the next step.

José Valim

unread,
May 14, 2023, 2:58:25 AM5/14/23
to elixir-l...@googlegroups.com
One addition: “features” makes sense for Rust because the contents of its “module body” cannot be dynamic as in Elixir. So if they want to provide this feature in the first place, it must be done as part of the compiler.

Elixir can execute any Elixir code when defining modules, which is why it is possible to implement these features today without additional work in the compiler.

It is not that we don’t care or didn’t think about it. Those are different trade-offs, with their own strengths and weaknesses, and if we want to copy features from Rust, then those trade-offs need to be taken into account as part of a complete proposal.

Michał Śledź

unread,
May 14, 2023, 3:18:01 AM5/14/23
to elixir-l...@googlegroups.com
Sure thing, I just wrote as I thought that maybe you will say: that's a good idea, we were thinking about it, we had similar problems etc. etc. 

But because of a lot of questions and doubts it's clear that's the requester responsibility to propose detailed description of the API, take into account all pros and cons, describe how they will affect the whole ecosystem and whether the requested feature fits into the language concepts

--
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 elixir-lang-co...@googlegroups.com.

Yordis Prieto

unread,
May 14, 2023, 2:08:35 PM5/14/23
to elixir-lang-core
Here is the issue: the proposal has not elaborated on how those problems will be tackled (outside of dependency management). 

I wasn't trying to be in Solution-space, just sharing some ideas and pain points and trying to figure out if they could be solved simultaneously.


And don’t ask us to figure it out

When I said, "I trust you will figure it out," I trusted you would do the right thing. I didn't give you any command. My apologies if it came across as a Command, but I intended to say, "I trust you, but please don't discourage the ideas making assumptions about it" That's all.

> It is not that we don’t care or didn’t think about it. Those are different trade-offs, with their strengths and weaknesses, and if we want to copy features from Rust, then those trade-offs need to be taken into account as part of a complete proposal.

I don't disagree with that at all. That was the intent; discuss it. But if we make assumptions and take the position of "it is possible today," how could we discuss the trade-offs?


Application.ensure_feature would most likely be a wrapper around config.

I am not sure about the technicality underneath, but I was assuming that we can't just do that unless we reserve some key or something like that, so I was thinking in a completely different ets table for it, but sure, it could "feel" as simple as Config module, why not.

One way I was thinking of adding a key under the `mix.exs` to be able to have information:

```
defmodule H264.MixProject do
  use Mix.Project

  def project do
    [features: [:parser, :encoder, :native]] # maybe be able to add description for them also?!
  end
end
```

Be able to use that information when calling `Application.ensure_feature`. It would be just the Config API since it would require checking `mix.exs` and/or another ets table with the information about the feature. I guess that registering the Features at compile time instead of being statically defined in the `mix.exs` would become harder. I am unsure if that would be a good idea.

ExDoc and the Mix.Deps task could read such information to require dependencies or have documentation about it. It could be used behind `Config` package under another macro:

```
import Config
feature :h264, encoder: true
```

Or don't do that at all and you only get to activate them using `deps` and mess around with `Mix.env()` to correctly configure the features.

Probably activating "statically" in the mix.exs would be simple and easier to deal with.

defmodule MyApp.MixProject do
  use Mix.Project

  def project do
    [
      deps: [
        {:h264, "~> 0.10.0", features: [:encoder]}
      ]
    ]
  end
end


José Valim

unread,
May 14, 2023, 3:33:30 PM5/14/23
to elixir-l...@googlegroups.com
No worries, I didn't interpret it as a command. But it is clear there is an expectation issue: this mailing list should focus on concrete features and implementations. Once someone submits a proposal here, they are probably expecting a yes, no (and why so), or what needs to be considered/improved for the proposal to be accepted. So all feedback in here has been direct (and historically it has not been a problem).

I recommend the Elixir Forum if the goal is to bounce ideas and explore the problem space. We (the Elixir team) already have a lot on our hands and we probably won't be able to develop ideas into full proposals. So I don't want your trust to be misplaced. :)

> if we make assumptions and take the position of "it is possible today," how could we discuss the trade-offs?

The point of saying "it is possible today" is that, if you are going to propose something new, then at least it needs to be compared to what is possible today and explain how it improves on that. This, alongside the problem statement, is very important to ensure we are all on the same page.

Yordis Prieto

unread,
May 14, 2023, 3:59:06 PM5/14/23
to elixir-lang-core
I thought that the ideas were around the topic. Is there any particular issue with the information I shared that wouldn't help with the situation?

Christopher Keele

unread,
May 15, 2023, 2:22:51 PM5/15/23
to elixir-lang-core
> Is there any particular issue with the information I shared that wouldn't help with the situation?

Your thoughts are compelling and merit discussion!

It's just that there's a slippery slope in proposal conversations: between discussing a specific proposal (in this instance, Michal's original well-formulated one), and brainstorming and iterating on feedback to arrive at a new specific proposal. It's a fuzzy line, but one we have to draw at some point in any conversation as it goes on, as this mailing list is only for specific proposals.

It's nothing personal—it's just time to move conversation around building a new proposal to a more productive discussion-oriented forum, such as the Elixir Forums, or direct chat/emails with others working on a new idea!

Yordis Prieto

unread,
May 15, 2023, 8:52:00 PM5/15/23
to elixir-lang-core
In cases, the following code may exist (real production code):

```
defmodule MyModule.Error do

  # notice here
  if Code.ensure_loaded?(Ecto) do
    alias MyModule.Error.{ChangesetParser, ErrorList}
    @spec new(Ecto.Changeset.t()) :: MyModule.Error.ErrorList.t()
    def new(%Ecto.Changeset{} = changeset) do
      changeset
      |> ChangesetParser.parse()
      |> ErrorList.new()
    end
  end


end
```

Based on your proposal, use the following structure:

```elixir
features: [
  hls: [
    dependencies: [],
    modules: []
  ]
]
```

How could we configure it to depend on `Ecto` only for that function?

Zach Daniel

unread,
May 16, 2023, 12:01:17 AM5/16/23
to elixir-l...@googlegroups.com
I'd amend the proposal:

To make a dependency only present when a feature is used
```elixir
{:optional_dep, …, optional: [:feature1, :feature2]}
```

To use a dependency with features
```elixir
{:dep, …, features: [:feature1]}
```

And then build features into `Mix` (which is available at compile time) or `Application` similar to `Application.compile_env`. The reason it makes sense to build it into `Mix` is that as José pointed out it will have to be built into mix/hex for dependency resolution.

```elixir
if Mix.feature?(:feature1)  do
  defmodule Foo do
    …
  end
end
```




To unsubscribe from this group and stop receiving emails from it, send an email to elixir-lang-core+unsubscribe@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-core/0d6c0925-4394-43e3-a227-8b43ac10dc3an%40googlegroups.com.

Yordis Prieto

unread,
May 16, 2023, 2:19:53 AM5/16/23
to elixir-lang-core
It could be `Mix` rather than `Application.` I just used `Application` because of how `compile_env` works. Here is another example where I am curious about how the proposal would solve it:

```
defmodule MyModule.ErrorBuilder do
  
    # notice here the macro
  defmacro __using__() do
    defstruct [....]
 
    # notice here the usage
    if Code.ensure_loaded?(Ecto) do

      def new(%Ecto.Changeset{} = changeset) do
        attrs = 
          changeset
           |> ChangesetParser.parse()
      
        struct(unquote(__MODULE__), attrs)
      end
    end
  end
end
```

Also, I was thinking more around the lines of if Mix.feature?(:otp_name, :feature1) or Mix.feature?/1, not sure.

I intended to highlight that Elixir is a fully turing completed scripting programming language to build Elixir code itself due to macro expansion. I don't know how you could define all the static information using features: [hls: [dependencies: [], modules: ]]] when the values depend upon Compile-Time macro expansion. It could even download an entire OpenAPI Spec YAML file and construct an entire module. I am not making things app, https://github.com/elixir-tesla/tesla_openapi (Protobuf, Avro, and many other things that could do the same), so situations as I described, including or not Jason encoding, among many other things, are real situations that will happen.

`mix.exs#features` could put guide rails in the library code, enforcing to statically define the features, and use `Mix.ensure_feature!/2` to enable the such feature if you want the compilation branch to happen. It does not matter where you are at compile-time.

I am sorry I am coming back to what I said before. Still, I am trying to figure out how the proposal would work, considering macro expansions depending upon the execution of the compilation and such compilation dictating the needs of the dependencies.

I am going to observe from now on. I shared the last information I somehow forgot to share that was critical to making sense of whatever I was trying to do. My apologies. Hopefully, next time, my brain doesn't fail me.

I am trying my best! I am sorry.

Zach Daniel

unread,
May 16, 2023, 6:52:37 AM5/16/23
to elixir-l...@googlegroups.com
Yes, if you want something with maximal flexibility you’d use application config and regular optional dependencies. The idea is to find a middle ground. Because we cannot run arbitrary code every time we want to solve versions. A package published to hex must know *all* potential dependencies.


Zach Daniel

unread,
May 16, 2023, 6:54:02 AM5/16/23
to elixir-l...@googlegroups.com
But also I think we should remove the `module` part from the proposed behavior. That’s the point I’m making, it’s not flexible as you’ve pointed out. But the features-> deps part must be static and simple.


On Tue, May 16 2023 at 6:52 AM, Zach Daniel <zachary....@gmail.com> wrote:
Yes, if you want something with maximal flexibility you’d use application config and regular optional dependencies. The idea is to find a middle ground. Because we cannot run arbitrary code every time we want to solve versions. A package published to hex must know *all* potential dependencies.

Yordis Prieto

unread,
Jul 15, 2023, 6:11:50 PM7/15/23
to elixir-lang-core
Considering releases, we would probably need to generate a static artifact to let us know what features were enabled when it was compiled without running the app. It is helpful when things go wrong in production.

Also, would this feature be something that Erlang itself could benefit from? OTP and Elixir teams could introduce "Release Channels Feature Flags," where people could opt-in to test things ahead of time without committing to a feature per se.
Reply all
Reply to author
Forward
0 new messages