[erlang-questions] Improve $handle_undefined_function

Loïc Hoguin essen@REDACTED
Tue Jan 22 13:25:59 CET 2013


On 01/22/2013 01:10 PM, Vlad Dumitrescu wrote:
> On Tue, Jan 22, 2013 at 1:02 PM, Loïc Hoguin <essen@REDACTED
> <mailto:essen@REDACTED>> wrote:
>
>     On 01/22/2013 12:57 PM, Vlad Dumitrescu wrote:
>
>         Hi,
>
>         On Tue, Jan 22, 2013 at 12:10 PM, Loïc Hoguin
>         <essen@REDACTED <mailto:essen@REDACTED>
>         <mailto:essen@REDACTED <mailto:essen@REDACTED>>> wrote:
>
>              On 01/22/2013 07:34 AM, Björn Gustavsson wrote:
>
>                  Why not use the existing -export() attribute and write like
>
>                  this:
>
>                  -export([monitor/2,demonitor/____1]).
>
>
>                  monitor(process, Pid) ->
>                       do_something.
>
>                  demonitor(Pid) ->
>                       do_something_else().
>
>                  So what would be the advantage of your version?
>
>
>              It still allows Evan Miller to write this:
>
>              -attr([first_name/1, last_name/1, ...]).
>
>              $handle_undefined_function(F, [Model]) ->
>                   {_, Value} = lists:keyfind(F, 1, Model),
>                   Value.
>
>
>         I'm sorry, but I don't think you are answering Björn's question. For
>         this particular case, why not write regular Erlang like
>
>         first_name(Model) -> get(first_name, Model).
>         last_name(Model) -> get(last_name, Model).
>         get(F, [Model]) ->
>               {_, Value} = lists:keyfind(F, 1, Model),
>               Value.
>         which is much clearer to understand. One argument might be that
>         there is
>         some duplication, but I think that it could be handled with much
>         more
>         elegance if we had abstract patterns implemented.
>
>         Do you have a more relevant example where using
>         $handle_undefined_function gives significant advantage?
>
>
>     That's a question about $handle_undefined_function in general, not
>     about this specific implementation proposal. Björn is the one who
>     wrote the current implementation that's now in master, I don't have
>     to tell him what can be done with it, he knows. I do have to tell
>     him how implementing it this way improves the usage, though. Which
>     is the sole reason of this thread.
>
>
> Maybe I'm confused, but your answer would make 100% sense if Björn's
> question would have been
>
> "
>    Why not use the existing -export() attribute and write like this:
>          -export([monitor/2,demonitor/1]).
> $handle_undefined_function(__monitor, [process, Pid]) ->
>              do_something();
>          $handle_undefined_function(__demonitor, Pid) ->
>              do_something_else().
> "
>
> My question is a follow-up on his own formulation, where your suggestion
> is compared with an implementation not using $handle_undefined_function
> at all.

And I answered it based on known potential uses. The snippet you quote 
was made to demonstrate the flaws in the current implementation, not to 
demonstrate an interesting use of the feature. It can be demonstrated 
using Evan's example too, for example:

$handle_undefined_function(F, [Model]) when is_list(Model) ->
     {_, Value} = lists:keyfind(F, 1, Model),
     Value;
$handle_undefined_function(F, Args) ->
     error_handler:raise_undef_exception(?MODULE, F, Args).

This would be an incorrect implementation of Evan's use for it, and 
nothing about it says "It's obvious!". And yet it's still wrong. Correct 
implementation would be:

$handle_undefined_function(F, [Model]) when is_list(Model) ->
     {_, Value} = lists:keyfind(F, 1, Model),
     Value;
$handle_undefined_function(F, Args) ->
     case lists:member({F, length(Args)},
             [{first_name, 1}, {last_name, 1}, ...]) of
         true -> erlang:error(badarg);
         false -> error_handler:raise_undef_exception(?MODULE, F, Args)
     end.

With my proposal he can write:

-attr([first_name/1, last_name/1]).

$handle_undefined_function(F, [Model]) when is_list(Model) ->
     {_, Value} = lists:keyfind(F, 1, Model),
     Value.

This makes error_handler properly handle undef errors, reduces the code 
needed to use the feature, allow tools to behave nicely when using the 
feature, etc.

As for why Evan would use $handle_undefined_function instead of creating 
many functions, that's for him to decide. But both implementations of 
$handle_undefined_function allow all known uses of the feature, yet only 
one gets error handling and tools support straight.

-- 
Loïc Hoguin
Erlang Cowboy
Nine Nines
http://ninenines.eu



More information about the erlang-questions mailing list