Oliver
I’m generating a module from a macro, like this:
defmodule WhereTheMacroIs do
defstruct [:same_for_all]
defmacro generate(name) do
quote do
defmodule unquote(name) do
def simplified_example(%WhereTheMacroIs{} = msg), do: msg.same_for_all
end
end
end
end
defmodule WhereIUseIt do
require WhereTheMacroIs
WhereTheMacroIs.generate(SomeOtherName)
def test, do: SomeOtherName.simplified_example(%WhereTheMacroIs{same_for_all: 42})
end
The problem I get is that the struct %WhereTheMacroIs{} will be name-expanded to %WhereIUseIt.WhereTheMacroIs{} when expanding macro WhereTheMacroIs.generate/1 - which is not what I want. I want all generated modules to use the same struct internally.
I googled for a while but I was unable to find a way to suppress this extension of the struct name.
This seems to happen even if an alias is used or not.
I’m using elixir 1.6.
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,
I know there is an approach for handling lists that allows for optimized traversal, but I can’t recall the specific method (somet...
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
Documentation
While reading the Scoped Routes section, I noticed that the documentation currently refers to a problem without explainin...
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
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
Corex is an accessible, unstyled UI component library for Phoenix that integrates Zag.js state machines using Vanilla JavaScript and Live...
New
With AI doing more of the implementation work, I’ve been wondering how much coding I should deliberately keep doing myself.
My main conc...
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 6- Show Best Posts
- Show All (oldest first)
- Show All (newest first)
NobbZ
You should update.
I do not understand. So you want to call
generatetwice and it shall generate the same module twice as well? This will cause warnings during compilation and also can cause weird races when the modules happen to have the same name, but different Implementation.Oliver
I can’t update easily. Bureaucracy reasons, unfortunately. (Also, would that solve my problem…?)
This was a simplified example. In the concrete example I have a central data structure - the data type does not change. So I want to re-use the struct for it. I still can combine the same structure with different callbacks (given as macro params) and define this under a new name.
The example already allows injecting a name to each expansion of generate/2 anyway, so name collisions are excluded. But my real problem is the struct.
NobbZ
Oh, I do only realize now that you use the
defstructoutside of the module.So you can either use
unquote(__MODULE__)(if I remember expansion rules correctly) or useElixir.WhereTheMacroIsto specify fully qualified module name.It wouldn’t solve your problem, yes. But I never understood the bureaucracy behind the staying outdated philosophy… Though I have to deal with it quite often due to my day work… One of our customers is still using Java5…
Oliver
Thank you.
I also figured it might be less problematic to only define function defs in the
quoteblock instead of adding thedefmodule- I’ll probably refactor to something more like the__using__/1macro in GenServer.Thanks for the tip with the
Elixir.! I saw this somewhere but it didn’t click in my brain…As for the bureaucracy… To unroll a new elixir version to our central infrastructure I would have to go through hoops involving one or two months time of waiting, and so far 1.6 has proven to be a quite blessed version.
dimitarvp
Okay, but why would you want to duplicate the same
structdefinition in every module? Shouldn’t it stay defined only once and just be used by the generated modules?Maybe I misunderstand but it does look like you are trying to copy the same struct definition for each module.
Oliver
Hi, dimitarvp.
I actually wanted to re-use the same struct definition in each module - not the
defstructstatement but simply the struct itself.I ended up doing something like below to achieve my goals. This is not what I was working on but follows the same principles:
The data structure itself (SimpleTree) is given, but operations on the actual values can still be generic and overridden. One can define only the parts that change in another module - here the order of elements. How the tree is built doesn’t change, but what kinds of values are in it and how they are ordered can be defined by the user.
In my own project I aimed to re-use the equivalent of
%SimpleTree{}because the complex data structure will remain the same while the types and operations on the leaves needed to be flexible. The problem I encountered was that when puttingdefmodulein aquoteblock that the struct names expanded to include the names of the enveloping module. (NobbZ’ advice about prefixingElixir.solves that particular issue.) But in the end what I wanted to achieve was easier done by a construct like I shared above - it just took some re-thinking my approach.For the sake of example I implemented two different kinds of operation:
add/2: Needs a functionorder/2defined in the module whereuse SimpleTreeis done. It must be defined inside the__using__/1macro.to_list/1: Depends solely on the structure of the data itself. It can be effectively defined outside the__using__/1macro. (So I actually pull it in withdefdelegateinstead of defining it inside the macro.)Both re-use the
%SimpleTree{}struct - it is only defined once. No multiple definitions of the same struct even if used in different modules. ModuleSimpleTreeknows nothing much about the data inside the value field - except that it is not another%SimpleTree{}struct (because that would break the algorithms). All the specifics regarding the actual values inside the tree are externalized to the one invokinguse SimpleTree. This makes it a similar pattern to C++ generic programming.(I didn’t compile my example, it was just the best I could think of when trying to show what I was trying to actually do.)