Erlang itself provides an interface that can be used to check whether the module has an export function. This interface is Erlang: function_exported/3, but this interface is often unavailable. The problem is reproduced below:
1> erlang:function_exported(crypto,start,0).false2> crypto:start().ok3> erlang:function_exported(crypto,start,0).true
Note: The example does not mean that you must crypto: Start () to use this function, but that this function does exist.
Now, let's take a look at Erlang's description of this interface: returns true if the module is loaded and contains an exported function/Arity; otherwise false. returns false for any BIF (functions implemented in C rather than in Erlang ). in other words, if a module has not been loaded, the Erlang: function_exported/3 function cannot be used. Many modules are not loaded to the system at Erlang startup and are loaded only when they are used. Therefore, this check may result in incorrect export function interfaces.
If you want to determine whether the module has an export function, you can write it as follows to use it normally.
-module(test).-compile(export_all).function_exported(Module, Function, Arity) ->case erlang:module_loaded(Module) oftrue ->next;_ ->code:load_file(Module)end,erlang:function_exported(Module, Function, Arity).
In addition, if the module is changed to BIF, it cannot be determined. However, we don't have to worry too much about this. None of the functions we write will be BIF.
Finally, we will discuss why Erlang: function_exported/3 can only check loaded modules? To implement hot update and replace the New and Old codes, Erlang maintains a global hash table to describe the module's function export information. As long as the loaded modules are loaded, information will be recorded in the hash table, saving the information will also consume a certain amount of memory overhead, and the hash algorithm itself may conflict with each other, the more elements, the higher the possibility of conflict. To solve the conflict, the bucket or linked list will be introduced. In this way, to ensure that key values are scattered, it will waste a lot of space, otherwise it will affect the search efficiency. Therefore, Erlang only records the information of the loaded modules, and the other modules are loaded when they are used. Erlang: function_exported/3 is a BIF function, which can be found in ERTs \ emulator \ Beam \ BIF. C:
BIF_RETTYPE function_exported_3(BIF_ALIST_3){ if (is_not_atom(BIF_ARG_1) || is_not_atom(BIF_ARG_2) || is_not_small(BIF_ARG_3)) { BIF_ERROR(BIF_P, BADARG); } if (erts_find_function(BIF_ARG_1, BIF_ARG_2, signed_val(BIF_ARG_3), erts_active_code_ix()) == NULL) { BIF_RET(am_false); } BIF_RET(am_true);}
Erts_find_function is implemented in ERTs \ emulator \ Beam \ export. C:
/* * Find the export entry for a loaded function. * Returns a NULL pointer if the given function is not loaded, or * a pointer to the export entry. * * Note: This function never returns export entries for BIFs * or functions which are not yet loaded. This makes it suitable * for use by the erlang:function_exported/3 BIF or whenever you * cannot depend on the error_handler. */Export* erts_find_function(Eterm m, Eterm f, unsigned int a, ErtsCodeIndex code_ix){ struct export_templ templ; struct export_entry* ee; ee = hash_get(&export_tables[code_ix].htable, init_template(&templ, m, f, a)); if (ee == NULL ||(ee->ep->addressv[code_ix] == ee->ep->code+3 && ee->ep->code[3] != (BeamInstr) BeamOp(op_i_generic_breakpoint))) { return NULL; } return ee->ep;}
Here, export_tables is a global variable or export. C, where code_ix is used to control the code version. If there is time, we will discuss the Erlang hot update mechanism.
static IndexTable export_tables[ERTS_NUM_CODE_IX]; /* Active not locked */
Therefore, Erlang: function_exported/3 only searches for the hash table of the export function and returns true if no value exists.
Reference: http://blog.csdn.net/mycwq/article/details/40663737
Erlang determines the module export Function