0
votes

Since attributes are inlined once the module is compiled, I assume their values are constant. If possible, I'd like to define an attribute in terms of previously created attributes. I also want to be able to access them from the outside, my current approach is this

@required_fields ~w(email)
@optional_fields ~w(password role name last_name age country)

def required_fields, do: @required_fields
def optional_fields, do: @optional_fields

@all_fields required_fields ++ optional_fields
def all_fields, do: @all_fields

but I get this error

== Compilation error on file web/models/user.ex == ** (CompileError) web/models/user.ex:22: undefined function required_fields/0 (elixir) expanding macro: Kernel.@/1 web/models/user.ex:22: AristaServer.User (module) (elixir) lib/kernel/parallel_compiler.ex:97: anonymous fn/4 in Kernel.ParallelCompiler.spawn_compilers/8

Any way to achieve something similar? I don't want to recalculate the all_fields list everytime, seems wasteful. Also, I don't want to have to copy and past both list into a third list, looks error prone.

2

2 Answers

2
votes

Unless you've run a benchmark, your intuitions about what is "wasteful" in elixir are probably wrong. I know that has been the case for every benchmark I've run. Just do this and worry about what is fast or slow after it's working.

 def all_fields, do: required_fields ++ option_fields

https://en.wikiquote.org/wiki/Donald_Knuth

My thinking is that using Module attributes is likely more wasteful of memory since those get converted to multiple items in the code. If you leave it in a variable, it only gets created once in memory. But that is just a guess.

However if you really want to combine module attributes, you can do it like this.

@all_fields @required_fields ++ @optional_fields
def all_fields, do: @all_fields

Your problem arises because you can't use a function from the module to define a module attribute.

1
votes
@required_fields    ~w(email)
@optional_fields    ~w(password role name last_name age country)
@all_fields         @required_fields ++ @optional_fields


def required_fields, do: @required_fields
def optional_fields, do: @optional_fields
def all_fields,      do: @all_fields

I doubt you need both module attributes and public methods; consider using only one (If you use them within the module only, module attributes should do the job, otherwise you should go with public methods).