2

I come from a Java and Ruby background and I was wondering if there is any equivalent of "method_missing" in Erlang. I have looked at the documentation and the closest I can see is the use of erl_eval and erl_parse, but I wanted to know if there is any other way?

yazz.com
  • 57,320
  • 66
  • 234
  • 385

5 Answers5

18

There is the 'error_handler' module which is called when you attempt to call an undefined function.

process_flag(error_handler, Module).

The module needs to export undefined_function/3 and undefined_lambda/3. You can see how this should be implemented in the standard handler module, error_handler.

You need to be careful in your own error_handler not to break the standard code loading system. Erlang usually tries to load the module from an undefined function error and re-run the function before giving up and signalling an error. You usually want to try the standard error_handler first and fall back to your new behaviour if that fails.

archaelus
  • 7,109
  • 26
  • 37
4

archaelus pointed in a good direction, but if you prefer not to meddle with the error_handler, it does support a nice callback routine notifying the module being called that there was an attempt to call an undefined function, which seems quite handy.

https://github.com/erlang/otp/blob/maint/lib/kernel/src/error_handler.erl#L139

So if you add this in a module:

'$handle_undefined_function'(Func, Args) ->
     io:format("Called undefined function '~p' with args ~p.~n", [Func, Args]).

It'll print out a message whenever a call is made to a undefined function in that module.

Kaos
  • 984
  • 7
  • 17
  • 2
    Maybe this didn't exist when the question was originally asked, but this is definitely the right answer now. +10 if I could. – Ryan Stewart Jun 20 '14 at 16:08
3

If you are into "defensive coding", you can call Module:module_info(exports) to see if the function you're about to call is exported or not.

Zed
  • 57,028
  • 9
  • 76
  • 100
  • Useful tip, I tried this and it does provide useful information. Is there any way I can dynamically add a method to this list (to a module I mean) then, as that could be useful – yazz.com Jan 18 '10 at 07:11
  • Check out smerl: http://code.google.com/p/erlyweb/source/browse/trunk/src/smerl/smerl.erl – Zed Jan 18 '10 at 19:03
1

Erlang has functions not methods and generally trying to call an undefined function is considered to be an error.

The compiler generates an error if you try to call a non-existent function within the same module. Trying to call a function in another module will generate an error at runtime, the undef error. How you wish to handle such an error depends on your application.

rvirding
  • 20,848
  • 2
  • 37
  • 56
  • So this looks promising. So does this mean that a "function_missing" method could be created for external modules which is invoked at runtime? – yazz.com Jan 18 '10 at 07:12
  • Yes, it could. See @archaelus answer earlier for more details. Be warned though that messing with the error_handler could completely ruin the automatic code loading and really mess up the system if it is not 100% right. – rvirding Jan 18 '10 at 21:30
0

I'm using a similar pattern on the calling side where a module may supply a log level classification function (which may return invalid results). I do it like this:

-spec categorize(atom(), integer()) -> log_classification().
categorize(Module, Code) ->
    case catch(Module:ns_log_cat(Code)) of
        info -> info;
        warn -> warn;
        crit -> crit;
        _ -> info % Anything unknown is info (this includes {'EXIT', Reason})
        end.

Since there isn't a method (in general, you could certainly create an OO behavior and implement it with messages and then have method_missing, the callee doesn't know I attempted anything, so it can't interpret it.

Dustin
  • 89,080
  • 21
  • 111
  • 133
  • Is this the same as a default clause in a case statement?? – yazz.com Jan 18 '10 at 07:08
  • In this case, I'm matching three known good values and then dealing with any other case (including exceptions and exits) as a default. I use `_` because I don't care about the results. – Dustin Jan 18 '10 at 18:31