walkr
Hello,
I need some help with the following problem (Bascially I want to store at compile time all modules using some other module, along with their opts).
defmodule Root do
@modules %{} # Mapping from __MODULE__ to opts
def __using__(opts) do
quote do
@opts unquote(opts)
def hello(), do: "Hello from #{__MODULE__}"
# How do I store __MODULE__ and its @opts
# inside Root.@modules?
# ...
end
end
def modules_using_me: @modules
end
defmodule A do
use Root, id: A1
end
defmodule B do
use Root, id: B1
end
Then to get the modules __using__ Root I would call
iex> Root.modules_using_me()
%{A: [id: A1], B: [id: B1]}
OR
iex> SomeOtherModule.modules_using_root()
%{A: [id: A1], B: [id: B1]}
Could anyone give me some ideas? I already tried to accumulate into a Root attribute all other modules, but obviously it fails since Root module is already compiled.
Thank you!
Trending in Questions
I’m working on a project that simulates the bumbl example in the programming phoenix book. It acts almost like an email client. We have a...
New
Hello!
Could someone please give me a help/sample code, how to delete a file from s3 using waffle/waffle_ecto from Phoenix app.
I creat...
New
I’m seeing that a list inside a Kino.DataTable will be interpreted as a charlist, even if the Kino.configure() is set to charlists: :as_l...
New
So my question is quite simple and i have found no conclusive answer on forum, google or AI.
Should we use :erlang.float for Integer to ...
New
Hi, I’ve just set up an application with ash_authentication. There is only magic link strategy for now, so there is no confirmation add o...
New
Hello,
I know there is an approach for handling lists that allows for optimized traversal, but I can’t recall the specific method (somet...
New
If a change or preparation module uses Ash.Changeset.get_argument/2 or Ash.Query.get_argument/2 (or any of the other get_argument functio...
New
Other Trending Topics
I am happy to introduce the very α version of the new programming language compiled to BEAM.
Welcome Cure.
It has literally three kille...
New
Hi there! We created Gust: A task orchestrator inspired by Airflow.
For those who have never heard about Aiflow, it’s a Python-based wor...
New
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
Xamal is a deployment tool for Elixir apps that deploys native releases to bare metal servers over SSH. It’s a port of GitHub - basecamp/...
New
Hello everyone. After busy few months I am happy to announce v0.1.0 of Emerge & Solve.
They are GUI (Emerge) and State management (S...
New
Corex is an accessible, unstyled UI component library for Phoenix that integrates Zag.js state machines using Vanilla JavaScript and Live...
New
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #library
- #deployment
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #elixirconf
- #channels
- #exunit
- #discussion
- #code-sync
- #podcasts
- #javascript
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixirconf-us
- #ai
- #blog-post
- #elixir-ls
- #phoenix_html
- #iex
- #graphql
- #genstage
- #websockets
- #supervisor
- #advent-of-code
- #distillery
- #processes
- #api
- #forms
- #hex
- #security
- #metaprogramming










Showing Posts 1 to 7- Show Best Posts
- Show All (oldest first)
- Show All (newest first)
christhekeele
As you observe,
Rootcannot know what modulesuseit at compile time, because it must first be compiled itself. Indeed, at compile time only moduleAcould know if it usedRoot.You can leverage module attributes to ask
Awhich modules it has used—example code for that here.Alternatively, since
Aknows what it’s used, you could inject that information into other modules thatuse Aif you take control of its__using__macro. This allows a module that uses bothAandBto know what modules they respectively have used. This is pretty abstract and hard to explain—I have example code demoing the concept here.walkr
Thank you for your reply @christhekeele. Unfortunately it doesn’t address my challenge. I need a way to record all the modules that are
__using__theRootmodule. Also, these modules are not to be used any further like in your second demo.christhekeele
I’m not sure that’s possible. When
Root.__using__is expanded, the only context it has access to is the module using it (Ain our example). So any tracking you want to do must occur withinA.There are only two ways I’m aware of to try to pass information
Aknows about to modules at compile time: using a macro defined inA(like giving it its own__using__macro and using it elsewhere); or a@before_compilemacro callback (which must come from an already compiled module as well).I understand your challenge pretty well—since I developed both of those examples a couple of years ago grappling with the same problem. Despite a lot of metaprogramming since then, I haven’t been able to find a way to accomplish exactly what you want in pure Elixir, and those techniques sufficed.
Ultimately I’m pretty sure the problem is intractable, because of the core problems:
Rootmust be compiled to be used__using__modules know whenRootis usedSo all you can really do when
Rootis used is to push that information around. You can put it inA, or use other techniques to put it in other modules, but by definition and the need for an acyclic module graph, you cannot ever put that information intoRootitself.christhekeele
That isn’t to say you couldn’t use techniques outside of pure compile-time Elixir macros to store this information somewhere. The obvious example that comes to mind is a file somewhere. Alternatively, the closest data store adjacent to pure Elixir that is available when the Elixir compiler is executing is
:ets. However, no matter how you handle it you run in to the issue where whenever during compilation you need the compiler to access that information, you can’t be fully sure that all modules that would contribute to it have finished compiling.walkr
I don’t need the list of modules at compile time (although that would be a bonus) but rather at runtime. I have a
GenServerthat needs this information. Let’s call itGS. I tried to inspect all loaded modules atGS’sinitvia:code.all_loaded, call some special function I inserted insideRoot’s__using__, however it looks like not all modules are loaded at the timeGSis initialized, thus I don’t get a complete picture. Note:GSis started in one app, whileAandBin another, probably that’s whyGSdoesn’t see all loaded modules.mbuhot
Your problem sounds similar to protocol consolidation. You might find some inspiration in GitHub - OvermindDL1/protocol_ex: Elixir Extended Protocol · GitHub which has a custom mix compiler task that scans the beam files for modules that declare implemtations of a protocol.
OvermindDL1
I can easily add a function that returns all implementations of the given protocol too (I think I have it in a descriptor but it’s not really ‘public’ stuff?), but if that is the only feature you are needing then the normal elixir protocols already has that feature too.
But yeah, the scanner part itself could easily do that, copy it into your project and just have it be a compiler that generates the information necessary after everything else is already compiled.