Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Erlang: Forced to make method public, why?

Tags:

erlang

I am following Joe Armstrong's book Programming Erlang, 2nd Edition, where we make a file server.

My code:

-module(afile_server).
-author("harith").

%% API
-export([start/1]).

start(Dir) ->  spawn(afile_server, loop, [Dir]).

loop(Dir) ->
    receive
        {Client, list_dir}  ->
            Client ! {self(), file:list_dir(Dir)};
        {Client, {get_file, File}}  ->
            File_Path = filename:join(Dir, File),
            Client ! {self(), file:read_file(File_Path)}
    end,
    loop(Dir).

As we can see, loop is a private method and should not be exposed to the outside world. Now when I run this, I get:

1> FileServer = afile_server:start(".").
<0.33.0>

=ERROR REPORT==== 3-Jan-2015::06:58:56 ===
Error in process <0.33.0> with exit value: {undef,[{afile_server,loop,["."],[]}]}

2> 

But when I make loop public as:

-module(afile_server).
-author("harith").

%% API
-export([start/1, loop/1]).

start(Dir) ->  spawn(afile_server, loop, [Dir]).

loop(Dir) ->
    receive
        {Client, list_dir}  ->
            Client ! {self(), file:list_dir(Dir)};
        {Client, {get_file, File}}  ->
            File_Path = filename:join(Dir, File),
            Client ! {self(), file:read_file(File_Path)}
    end,
    loop(Dir).

then it runs fine:

1> FileServer = afile_server:start(".").
<0.33.0>
2> 

Does spawn required the method to be public? I guess yes because it runs it as:

afile_server:loop(Dir)  

but I want to make sure there is nothing else wrong.

like image 294
daydreamer Avatar asked Dec 05 '25 13:12

daydreamer


2 Answers

If you use spawn with M:F:A you are forced to set loop public.

You can avoid it in this way:

-module(afile_server).
-export([start/1]).

start(Dir) ->  spawn(fun() -> loop(Dir) end).

loop(Dir) ->
    receive
        {Client, list_dir}  ->
            Client ! {self(), file:list_dir(Dir)};
        {Client, {get_file, File}}  ->
            File_Path = filename:join(Dir, File),
            Client ! {self(), file:read_file(File_Path)}
    end,
    loop(Dir).

If your methods don't have arguments you can also use:

spawn(fun loop/0),

A good reason to use the version with M:F:A consists in the fact that whenever you load a new version of the same module this new version will be called. Otherwise you will keep on calling the old module.

like image 143
user601836 Avatar answered Dec 07 '25 15:12

user601836


Another reason to for having the function exported, even if it is in the same module, is that with spawn you create a completely new context and environment so it is reasonable to have to call an exported function.

like image 43
rvirding Avatar answered Dec 07 '25 15:12

rvirding