stjefim

stjefim

Get function name, module and arity from function capture

Hello!

I want to “save function” (module, name, arity) to the database to be able to call it later, potentially after BEAM was restarted. My plan is to use Functions.capture(module, function_name, arity) to be able to call the function after “loading” from the database.

How can I obtain module, function name and arity from a function capture (e.g. &MyModule.my_function/0) to “save function”? I have found Functions.info(fun) function, however, the documentation has a note saying that it should be used for debug only. What are the reasons it is debug only? What are the alternatives?

Marked As Solved

jswanner

jswanner

The underlying Erlang function docs says it’s “mainly” for debugging:

This BIF is mainly intended for debugging, but it can sometimes be useful in library functions that need to verify, for example, the arity of a fun.

That said, the :telemetry library uses it to verify you supply an external function as a handler.

Also Liked

al2o3cr

al2o3cr

The specific thing you’re looking for is :erlang.fun_info:

iex(1)> f = &String.capitalize/1
&String.capitalize/1

iex(2)> :erlang.fun_info(f)
[module: String, name: :capitalize, arity: 1, env: [], type: :external]

Note that it gives a possibly-unexpected result if given a capture that uses &n forms:

iex(3)> f2 = &String.starts_with?(&1, "foo")
#Function<42.39164016/1 in :erl_eval.expr/6>
iex(4)> :erlang.fun_info(f2)
[
  pid: #PID<0.0.0>,
  module: :erl_eval,
  new_index: 42,
  new_uniq: <<74, 179, 14, 23, 76, 2, 152, 184, 122, 207, 206, 42, 63, 68, 21,
    64>>,
  index: 42,
  uniq: 39164016,
  name: :"-expr/6-fun-3-",
  arity: 1,
  env: [
    {3, %{}, {:value, &:elixir.eval_local_handler/2},
     {:value, &:elixir.eval_external_handler/3}, %{},
     [
       {:clause, 3, [{:var, 3, :_capture@1}], [],
        [
          {:call, 3,
           {:remote, 3, {:atom, 3, String}, {:atom, 3, :starts_with?}},
           [
             {:var, 3, :_capture@1},
             {:bin, 3,
              [{:bin_element, 3, {:string, 3, ~c"foo"}, :default, :default}]}
           ]}
        ]}
     ]}
  ],
  type: :local
]
bartblast

bartblast

Creator of Hologram

Hey @stjefim, are you aware of Kernel.apply/3?

derek-zhou

derek-zhou

I don’t think there is a general solution as function can be anonymous. Also, storing function in a db may not be the best idea. Code will change, db record last for a long time. Also, think of the security implication.

stjefim

stjefim

Thank you, it will be useful after “loading function” - no need to do Functions.capture.

derek-zhou

derek-zhou

That’s not possible. Because you can’t turn a function value back to MFA, just like you can’t turn a value back to the variable name.

You can store the function value itself though:

binary = :erlang.term_to_binary(&MyModule.my_function/0)
# store in db
fun = :erlang.binary_to_term(binary)
fun.()

However, as I mentioned above, that’s a big foot gun.

Where Next?

Popular in Questions Top

Brian
What is the proper way to load a module from a file in to IEX? In the python world, doing something like this pretty standard: from ....
New
gshaw
What is the idiomatic way of matching for not nil in Elixir? E.g., First way: defp halt_if_not_signed_in(conn, signed_in_account) when...
New
dokuzbir
Hello, I am trying to convert my lists to string without losing brackets.For start i have 3 map. They look like these buyer = %{ id: ...
New
vertexbuffer
Hello, can anybody help here..? I have a list of players and I what to delete an element, but every for loop the list is reverting to ori...
New
mgjohns61585
Could someone help me? I'm making my first elixir program, number guessing game. I can't figure out how to convert the user's guess from ...
New
shahryarjb
Hello, I have map which I want to convert it to string like this: the map: %{last_name: "tavakkoli", name: "shahryar"} the string I ne...
New
fireproofsocks
Forgive me if this is obvious, but how does one delete a database record WITHOUT selecting it first? https://hexdocs.pm/ecto/Ecto.Repo.h...
New
ovidiubadita
Hey all, I discovered Elixir and I love it. I always wanted to learn a functional programming and I intended to go for Haskell, but afte...
New
sabri
Can someone explain the settings of pool_size of Ecto in config file? and what is the recommend size? Thanks
New
idi527
I’ve been re-reading swift book again and noticed that multiline strings there don’t have a trailing line break, unlike in elixir iex(2)...
New

Other popular topics Top

Qqwy
Update: How to use the Blogs &amp; Podcasts section You can post links to your blog posts or podcasts either in one of the Official Blog...
3268 119930 1237
New
sorentwo
Hello! tl;dr Announcing Oban, an Ecto based job processing library with a focus on reliability and historical observability. After spen...
977 41022 311
New
ycv005
I have followed this StackOverflow post to install the specific version of Erlang. And When I am running mix ecto.setup then getting fol...
New
grych
Hi folks, Few months ago I have announced the proof-of-concept of the library to manipulate the browsers DOM objects directly from Elixi...
639 49522 488
New
KronicDeth
Elixir plugin for JetBrain’s IntelliJ Platform (including Rubymine) This is a plugin that adds support for Elixir to JetBrains IntelliJ...
289 35421 110
New
jononomo
I am trying to figure out how Mix knows whether the environment is test, dev, or prod -- where is this set? Thanks.
New
myronmarston
The Elixir Typespec docs show the following syntax for keyword lists in typespecs: # ... | [key: type] # keyword lis...
New
chensan
I have a User schema with a :from_id field set to type :string: defmodule TweetBot.Repo.Migrations.CreateUsers do use Ecto.Migration ...
New
vonH
When I run the Plug and I recompile I wind up having to use Ctrl C to quit iex and start again. Witht the help of rlwrap I can use the cu...
New
johnnyicon
Hi all, I've just started learning Elixir and Phoenix Framework, so please pardon my n00bness at this stage. I'm trying to use Postg...
New

We're in Beta

About us Mission Statement