Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'bjorn/kernel/undefined-function-handler/OTP-10617'
* bjorn/kernel/undefined-function-handler/OTP-10617: Teach error_handler to call '$handle_undefined_function'
- Loading branch information
Showing
4 changed files
with
119 additions
and
41 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,68 @@ | ||
| %% | ||
| %% %CopyrightBegin% | ||
| %% | ||
| %% Copyright Ericsson AB 2013. All Rights Reserved. | ||
| %% | ||
| %% The contents of this file are subject to the Erlang Public License, | ||
| %% Version 1.1, (the "License"); you may not use this file except in | ||
| %% compliance with the License. You should have received a copy of the | ||
| %% Erlang Public License along with this software. If not, it can be | ||
| %% retrieved online at http://www.erlang.org/. | ||
| %% | ||
| %% Software distributed under the License is distributed on an "AS IS" | ||
| %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See | ||
| %% the License for the specific language governing rights and limitations | ||
| %% under the License. | ||
| %% | ||
| %% %CopyrightEnd% | ||
| %% | ||
| -module(error_handler_SUITE). | ||
|
|
||
| -export([all/0,suite/0,groups/0,init_per_suite/1,end_per_suite/1, | ||
| init_per_group/2,end_per_group/2, | ||
| undefined_function_handler/1]). | ||
|
|
||
| %% Callback from error_handler. | ||
| -export(['$handle_undefined_function'/2]). | ||
|
|
||
| suite() -> [{ct_hooks,[ts_install_cth]}]. | ||
|
|
||
| all() -> | ||
| [undefined_function_handler]. | ||
|
|
||
| groups() -> | ||
| []. | ||
|
|
||
| init_per_suite(Config) -> | ||
| Config. | ||
|
|
||
| end_per_suite(_Config) -> | ||
| ok. | ||
|
|
||
| init_per_group(_GroupName, Config) -> | ||
| Config. | ||
|
|
||
| end_per_group(_GroupName, Config) -> | ||
| Config. | ||
|
|
||
|
|
||
| %%----------------------------------------------------------------- | ||
|
|
||
| undefined_function_handler(_) -> | ||
| 42 = ?MODULE:forty_two(), | ||
| 42 = (id(?MODULE)):forty_two(), | ||
| {ok,{a,b,c}} = ?MODULE:one_arg({a,b,c}), | ||
| {ok,{a,b,c}} = (id(?MODULE)):one_arg({a,b,c}), | ||
| {'EXIT',{undef,[{?MODULE,undef_and_not_handled,[[1,2,3]],[]}|_]}} = | ||
| (catch ?MODULE:undef_and_not_handled([1,2,3])), | ||
| ok. | ||
|
|
||
| '$handle_undefined_function'(forty_two, []) -> | ||
| 42; | ||
| '$handle_undefined_function'(one_arg, [Arg]) -> | ||
| {ok,Arg}; | ||
| '$handle_undefined_function'(Func, Args) -> | ||
| error_handler:raise_undef_exception(?MODULE, Func, Args). | ||
|
|
||
| id(I) -> | ||
| I. |
209a479There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please reconsider this functionality, it will not be used for good in the long run.
Its usage applies to at best 1 out of 100 modules, and creates similar issues found with parameterized modules.
It exposes internals with regard to the raise_undef_exception while the dynamic function calling will make finding errors more difficult
and to put it plainly the error handler should not be calling functions in user modules.
If one calls an undefined function, it should just crash and not try to "handle it" as doing so would violate Erlang semantics.
This feature will simply scratch an itch and become a rash. -1
209a479There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm with DeadZen on this - from the perspective of both predictability and security, this gives me the willies.
If you must go down this road, I'd prefer that it be far more constrained (handlers can only go to certain types/names of modules, special compiler flags must be invoked, secret signs flashed, etc.).
That said, I still see this as potentially causing issues down the road...
-1
209a479There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no method_missing for erlang. This will be overused - 1
209a479There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Three cheers for $handle_undefined_function. This will make code generation in BossDB a million times easier. Who cares if you think it will be overused in other people's projects? It makes my life easier and doesn't affect yours. Mind your own business!
+1
209a479There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another -1 from me. This makes room for many unpredictable behaviours. For those who wants this behaviour: how hard is it to just create your own apply_with_handler(M, F, A)? Making error_handler calling functions is a terrible hack.
209a479There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This doesn't actually "makes room" — this behaviour has been available in a slightly more complex way for ages
209a479There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@evanmiller It affects mine because now if I use a library or an application that itself uses that, I'm not even sure the code will fail properly if I make a typo in a function name. And as this feature isn't supported by Dialyzer nor xref (and can't be), I will have no way to know whether I did wrote the function name badly, because the tool will always bark at me, whether the call is legit or not.
209a479There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@nox, following this logic,
applyshould be removed, too.Also, nobody forces you to use libraries you don't like :)
209a479There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As long as the call order is well-defined to always be the same (process-defined handler -> module-defined handler), there should be no big consistency problem.
There should be work done in order to make sure that a crash in the
'$handle_undefined_function'handler does not change the error type fromundefto whatever the crash was.In my opinion, this will allow to keep a more declarative type of error handling there while keeping the caller's expectations sane, and will put the burden of shoddy programming maintenance on the authors of the original handler, and not push it to the user of the library.
Let's imagine I use a module that used this feature, gets updated, and has a bug that breaks the functionality within
'$handle_undefined_function'. As the user of that module, I may get anything fromundefto whatever the handler uses and can generate (badarg,badarith,badfun, etc.). This can be very confusing to debug and manage.On the other hand, if the error is restricted to
undef, the unknown behaviour is pushed back on the maintainer of the library to figure out, and inspecting the module will show that the function is indeed missing. It breaks fewer expectations.I would also be in favor of a new error type of the kind
module_author_uses_features_he_or_she_is_not_understanding_please_blame_themto be returned to make the problem 100% obvious and embarrassing. I'm barely kidding here.I'm not against the idea, but -1 with the current implementation.
209a479There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like the feature. I hate the implementation. Here's a proposal for an hopefully better implementation of this feature, in a few short steps:
209a479There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the whole idea people use it for is that they don't know those function names ahead of time
209a479There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When you -extend you know what functions you don't implement. When you write functionality that has to go through the undefined handler you know which functionality do. In what case do you not know what goes through it?
209a479There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
209a479There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Evan is generating code. I'm sure if he can generate code for calling
first_namethen he can add an attribute listing it. He currently does it for exports, right? What's the difference?209a479There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please discuss issue at mailing lists. GitHub is fine for commenting but not for discussing.