[erlang-questions] What is the fastest way to check if a function is defined in a module?

Richard Carlsson carlsson.richard@REDACTED
Tue Mar 6 16:35:44 CET 2018


You also need to consider whether or not you want loading to be
automatically triggered by this check, or if you indend to ensure in some
other way that the modules you are checking are known to be loaded already.
Using "try Module:Function() catch ... end", if the function is not found
it will cause a trap to the error handler module which will first try to
load the module if it is not currently in memory. If you use only
erlang:function_exported/3, it will return "false" if the module is not yet
loaded.

If you assume that modules are usually loaded when you run the test, but
you'd like to load them automatically if needed, you can write a function
like this:

is_exported(M, F, A) ->
  case erlang:module_loaded(M) of
    false -> code:ensure_loaded(M);
    true -> ok
  end,
  erlang:function_exported(M, F, A).

(code:ensure_loaded() is slow compared to the fast call to
erlang:module_loaded(), even if the module is already in memory).

If it should be an error if the module cannot be loaded, you can add a
check that ensure_loaded(M) returns {module, M} and not {error,_}.

If you want to prevent repeated attempts to load a module that failed to
load the first time (since such attempted loads are slow), you could add
some kind of memoization, or even generate a dummy module containing no
functions, that you load instead so that subsequent calls return quickly.

        /Richard

2018-03-04 8:09 GMT+01:00 Metin Akat <akat.metin@REDACTED>:

> I haven't yet done rigorous testing with many processes, but what you are
> suggesting is the slowest so far (at least by the most naive way of
> measuring, while not under load) :
>
> 37> timer:tc(fun() -> lists:member({not_a_function, 1},
> Module:module_info(exports)) end).
> {514,false}
> 38> timer:tc(fun() -> try Module:not_a_function() catch error:undef ->
>  not_defined end end).
> {47,not_defined}
> 39> timer:tc(fun() -> erlang:function_exported(Module, not_a_function, 1)
> end).
> {8,false}
>
>
> The reason I'm asking is because I saw this gen_server:try_dispatch/3
> implementation and I am wondering what are the implications under heavy
> load and concurrency.
>
>
>
>
>
> On Sun, Mar 4, 2018 at 8:47 AM, Zachary Kessin <zkessin@REDACTED> wrote:
>
>> I realize that there is a race condition in that code, if someone reloads
>> the module at the wrong moment it could crash.
>>
>>
>>
>> Zach Kessin - CEO Finch Software
>> I boost sales with retail chatbots for fashion and cosmetics
>> +972 54 234 3956 <+972%2054-234-3956> / +44 203 734 9790
>> <+44%2020%203734%209790> / +1 617 778 7213 <+1%20617-778-7213>
>> Book a meeting with me <https://calendly.com/zkessin/chatbot>
>>
>> On Sun, Mar 4, 2018 at 8:37 AM, Zachary Kessin <zkessin@REDACTED> wrote:
>>
>>> You can use the function MODULE:module_info/1 something like
>>> is_defined(MyFunc, Arity, MODULE)->
>>>    Functions = MODULE:module_info(functions),
>>>    lists:member({MyFunc,Arity}, Functions).
>>>
>>> Where MyFunc is an atom of course
>>>
>>> You could also expand that to a call_function_if_defined_with_default/N
>>> but i will leave that to you
>>>
>>> Zach
>>>
>>>
>>> Zach Kessin - CEO Finch Software
>>> I boost sales with retail chatbots for fashion and cosmetics
>>> +972 54 234 3956 <054-234-3956> / +44 203 734 9790
>>> <+44%2020%203734%209790> / +1 617 778 7213 <+1%20617-778-7213>
>>> Book a meeting with me <https://calendly.com/zkessin/chatbot>
>>>
>>> On Sat, Mar 3, 2018 at 9:42 PM, Metin Akat <akat.metin@REDACTED> wrote:
>>>
>>>> I'm looking into this code: https://github.com/erlan
>>>> g/otp/blob/master/lib/stdlib/src/gen_server.erl#L631
>>>>
>>>> Seems like this try/catch clause is implemented with the idea that most
>>>> of the time it will succeed, as the callback module will have implemented
>>>> the corresponding callback function, so we will not have to go into the
>>>> exception clause where it needs to call erlang:function_exported/2 one more
>>>> time (presumably as an additional safeguard) which is more expensive than
>>>> an optimistic try clause.
>>>>
>>>> I am writing something very similar, where such a check (is a function
>>>> exported) will be performed by thousands/millions of processes on every
>>>> message, but in my case... it's quite probable that most of the time this
>>>> WILL raise the exception. In my case the function will be purely optional -
>>>> if defined, it will return a value. If not, a default value will be used.
>>>>
>>>> So my question is, how bad is this? I will test, but I'm still
>>>> interested if someone has any ideas (maybe do something completely
>>>> different).
>>>>
>>>> Other possibilities are:
>>>>
>>>> - Actually make the callback compulsory. I don't want to do that, as
>>>> the problem I'm solving with this project is "See, you don't have to
>>>> implement this boilerplate every time any more"
>>>>
>>>> -  Put the option in application env where the user can configure it on
>>>> startup.
>>>>
>>>>
>>>>
>>>> _______________________________________________
>>>> erlang-questions mailing list
>>>> erlang-questions@REDACTED
>>>> http://erlang.org/mailman/listinfo/erlang-questions
>>>>
>>>>
>>>
>>
>
> _______________________________________________
> erlang-questions mailing list
> erlang-questions@REDACTED
> http://erlang.org/mailman/listinfo/erlang-questions
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://erlang.org/pipermail/erlang-questions/attachments/20180306/4b648b5a/attachment.htm>


More information about the erlang-questions mailing list