I would avoid going this path, as the benefit you gain (1 line of code vs 3 lines of code) is not worth it, because it will make the code much less readable.
As I mentioned, I am in the process of adding 2 more attributes, are you suggesting to add snippets every time I need some sort of common attribute to all my components?
(that would be reasonable, I am just asking :))
In general, it’s still difficult for me to think at how to implement a “Parent Component” with common functionality (I would use a Parent class in the previous language I used, which comes with its own downsides).
Probably a false issue, but ~50 components are a lot when doing manual edits, it become tedious quickly.
I am not seriously suggesting it, I am saying it’s one of the potentially viable solutions just to illustrate that it would be too much to use macros here.
That would be a good candidate for a macro. Have that parent have defmacro __using__(opts \\ []) macro and inject code through it.
That way you can have all your 50+ components only have this line at the top:
use Parent, option_1: true, option_2: ["hello", "there"], option_3: :duh
…and the rest will be just their specific parts.
Or, if you are REALLY convinced that this is a strict parent-children relationship and that this will not change – i.e. you will never need multiple parents per one child – then you can just use Elixir’s protocols and apply a little violence.
Actually I would avoid using here __using__ as it is not necessary. I would something like this:
defmodule Attributes do
defmacro generic_attributes() do
quote do
attr :class, :string, default: ""
attr :id, :string, default: nil
attr :rest, :global
end
end
end
I don’t see much difference to be honest, you can just have a module named e.g. Parent.GenericAttributes and then use that.
OK that could be a good point but you gotta draw the line somewhere. Put some docs in the module that defines the __using__() or generic_attributes() and say “This should only be used to inject common attributes, please contact @dev_author to discuss other usages before modifying this code”. We’re not talking about some 50+ devs team after all.
I think generally speaking for someone who doesn’t write macros, it is easier to understand the variant of a macro vs use, as at the end of the day it does the same thing.
I think that limiting temptation is the best thing to avoid someone over-using macros, at least that is what I saw from my own experience.
Ah, no doubt, that’s what my first reply here alluded to as well. Though after OP elaborated it seems like their need could genuinely be served well with a macro.
IIUC if I put the common attributes in the __using__() I can’t have a module with many function components having their own common attributes,
while this is doable with a generic_attributes() one.
You are not wrong but I would be completely okay if one module’s only job was to inject code in others. Having huge modules doing many things with many code-injection macros is not exactly a win for readability and maintainability.
In the end it’s your call, and the difference can be easily handled.