enobat
Attributes with function name
Can you use custom attributes similar to @impl or @behaviour, but rather than using a callback function, only the function name is used (e.g. @description Mod.fun).
# A.ex
defmodule A do
use C
@description1 "function11 returns :ok"
def function1(_a) do
:ok
end
@description2 A.function1
def function2(_b) do
:ok
end
end
In the example above, the @description1 attribute is valid, since what follows is a string. Then, in @description2 fails since it tries to get a value, but instead I wish to get the name of the method (i.e. A.function1).
defmodule B do
@behaviour Bar
@callback foo
end
Some elixir modules are able to do something similar. For example, you can set modules/methods to @behaviour and @callback. Can something similar be created?
Thanks.
First Post!
Nicd
You could use a function reference there, like
@description &A.function1/1
But I’m wondering what you want to do with it? Obviously module A would then need to be compiled first.
Last Post!
enobat
I’m developing static checker, so all modules need to be compiled first, before analysed.
For example, the @description attribute can either be set to a string, or otherwise refer to another function (which I can process later on).
# A.ex
defmodule A do
use B
@description "function1/0 returns :ok"
def function1() do
:ok
end
@description A.function1
def function2() do
:ok
end
end
# B.ex
defmodule B do
defmacro __using__(_) do
quote do
import B
Module.register_attribute(__MODULE__, :description, accumulate: true, persist: true)
Module.register_attribute(__MODULE__, :test, accumulate: true, persist: true)
@after_compile B
end
end
def __on_definition__(env, _access, name, args, _guards, _body) do
IO.puts("Reached on_definition")
desc = Module.get_attribute(env.module, :description) |> hd()
Module.delete_attribute(env.module, :description)
Module.put_attribute(env.module, :test, {name, length(args), desc})
end
def __after_compile__(_env, bytecode) do
IO.puts("Reached after_compile")
# Gets debug_info chunk from BEAM file
chunks =
case :beam_lib.chunks(bytecode, [:debug_info]) do
{:ok, {_mod, chunks}} -> chunks
{:error, _, error} -> throw("Error: #{inspect(error)}")
end
# Gets the (extended) Elixir abstract syntax tree from debug_info chunk
dbgi_map =
case chunks[:debug_info] do
{:debug_info_v1, :elixir_erl, metadata} ->
case metadata do
{:elixir_v1, map, _} ->
# Erlang extended AST available
map
end
x ->
throw("Error: #{inspect(x)}")
end
dbgi_map[:attributes]
|> IO.inspect
end
end
This outputs the following. &A.function1/0 is saved which is what was needed:
[description: "function1/0 returns :ok", description: &A.function1/0]
Compared to the Elixir module, you can set functions directly @callback foo. Can something cleaner (without the &a/0) be achieved?
Popular in Questions
Other popular topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #websockets
- #supervisor
- #elixirconf-us
- #advent-of-code
- #distillery
- #processes
- #api
- #forms
- #metaprogramming
- #security
- #hex









