https://medium.com/about-erlang/how-private-are-erlang-private-functions-36382c6abfa4 Upgrade Open in app Home Notifications Lists Stories --------------------------------------------------------------------- Write About Erlang Published in About Erlang Roberto Aloi Roberto Aloi Follow May 18, 2018 * 3 min read How private are Erlang private functions? Today a tweet on my Twitter timeline caught my attention: Private functions in Erlang are private, for Science's sake! It's not like in Python where you add a couple of underscores here and there and suddenly, et voila, what two seconds ago was private is now public. In Erlang we had private functions in a safe for 25 years! There is no way someone can call a function that we declare as private! Or... Is there a way? [1] I'll show you It turns out that there is a not-so-straightforward way to call a private function in Erlang, assuming the code has been compiled with debug_info enabled. Let's see how things work. Let's start by defining a module named test. The module contains two functions, of which only one is exported: -module(test).-export([public/0]).public() -> i_am_public.private() -> i_am_private. Let's compile the module, ensuring we include debug information. Notice how including debug information is fairly common to do in Erlang, since many tools including debuggers, cross-reference tools and cover analysis tools require these information to work: $ erlc +debug_info test.erl test.erl:8: Warning: function private/0 is unused The compiler informs us that the private function is not accessible, which is expected. Let's now open a shell and try to invoke both functions: $ erl Erlang/OTP 19 [erts-8.3.5.3] [...]Eshell V8.3.5.3 (abort with ^G) 1> l(test). {module,test} 2> test:public. i_am_public 3> test:private(). ** exception error: undefined function test:private/0 We can invoke the public function, but not the private one. Nothing new. Let's now define a small anonymous function (I will explain what it does in a second) and let's bind it to the Open variable: 4> Open = fun(Module) -> Which = code:which(Module), {ok,{_,[{_,{_,A}}]}} = beam_lib:chunks(Module, [abstract_code]), {ok, Module, Binary} = compile:forms(A, [export_all]), code:load_binary(Module, Which, Binary) end. #Fun Let's then invoke the Open function, passing the test module as an argument: 5> Open(test). {module, test} Let's now try to access the private function: 6> test:private(). i_am_private. The safe is now wide open. [1] My gosh. So, what kind of black magic lays behind the Open function? Not much, actually. Let's look at it again: fun(Module) -> Which = code:which(Module), {ok,{_,[{_,{_,A}}]}} = beam_lib:chunks(Module, [abstract_code]), {ok, Module, Binary} = compile:forms(A, [export_all]), code:load_binary(Module, Which, Binary) end. After asking the code server for the absolute filename for the test module, we use the powerful beam_lib interface to extract the abstract syntax forms from the debug information contained in the test beam (remember we compiled it with the debug_info option)? We then recompile the module starting from those forms and by adding the notorious export_all option documented here, which causes all functions defined in the module to be exported. We reload the new version of the module and we're done. There are some corner case that, for simplicity, the Open function does not take care of in the above example, but you should get the gist of it. Happy hacking! 23 1 23 23 1 More from About Erlang My thoughts about Erlang Read more from About Erlang Get started [ ] Roberto Aloi Roberto Aloi 351 Followers Follow More from Medium Hasani Ade Hasani Ade FLOW [1] Angus Angus Acceptance Nazar Khimin Nazar Khimin FATA #13/ Value Proposition [0] (*'*'*) (*'*'*) W2: "Dear past self..." [1] Help Status Writers Blog Careers Privacy Terms About Knowable