Question

How can I pass the self parameter in Elixir in an OO like way?

For example I wrote this Erlang Javascript like object with garbage collection:

-module(o).

-export([n/0, g/2, s/3, d/1]).

-behaviour(gen_server).
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).

-record(state, {dictionary=dict:new()}).

-define(SERVER, ?MODULE).

-on_load(deps/0).

deps() ->
    AS = fun(Mod) ->
        try application:start(Mod) catch _Type:_What -> ok end
    end,
    [AS(Mod) || Mod <- [sasl, lager, resource]],
    ok.

n() ->
    case gen_server:start(?MODULE, {}, []) of
        {ok, Pid} ->
            Res = resource:notify_when_destroyed(Pid, {timeout, Pid}),
            {?MODULE, {Res, Pid}};
        Other ->
            Other
    end.

g(Key, {?MODULE, {_Res, Pid}}) ->
    gen_server:call(Pid, {g, Key}).

s(Key, Val, {?MODULE, {_Res, Pid}}) ->
    gen_server:cast(Pid, {s, Key, Val}).

d({?MODULE, {_Res, Pid}}) ->
    gen_server:cast(Pid, stop).

%% @private
init({}) ->
    {ok, #state{}}.

%% @private
handle_call({g, Key}, _From, State = #state{dictionary=Dict}) ->
    {reply, case dict:find(Key, Dict) of {ok, Val} -> Val; error -> error end, State};
handle_call(Request, _From, State) ->
    lager:info("handle_call discarded request: ~p", [Request]),
    {reply, {error, unknown_call}, State}.

%% @private
handle_cast({s, Key, Value}, State = #state{dictionary=Dict}) ->
    {noreply, State#state{dictionary=dict:store(Key, Value, Dict)}};
handle_cast(stop, State) ->
    {stop, normal, State};
handle_cast(Msg, State) ->
    lager:info("handle_cast discarded message: ~p", [Msg]),
    {noreply, State}.

%% @private
handle_info({timeout, Pid}, State) ->
    d({?MODULE, {res, Pid}}),
    lager:info("Garbage collection of object ~p", [Pid]),
    {noreply, State};
handle_info(Info, State) ->
    lager:info("handle_info discarded message: ~p", [Info]),
    {noreply, State}.

%% @private
terminate(_Reason, _State) ->
    ok.

%% @private
code_change(_OldVsn, State, _Extra) ->
    {ok, State}.

NOTE: I use https://github.com/tonyrog/resource.git for resource collection.

1> l(o).
... LOGS ...
{module,o}
2> O = o:n().
{o,{{resource,140524043665312,<<>>},<0.58.0>}}
3> O:s(a, b).
ok
4> O:g(a).
b
6> O:s(hello, fun() -> io:format("Hello World~n") end). 
ok
7> (O:g(hello))().
Hello World
ok
Was it helpful?

Solution

As far as I'm aware it's not possible to call modules in this way in Elixir. You must explicitly pass the self parameter for all of the calls. So to take your Erlang example to Elixir, it would look like:

iex> o = O.n()
{O, {{:resource, 140524043665312, <<>>}, <0.58.0>}}
iex> O.s(:a, :b, o)
:ok
iex> O.g(:a, o)
:b
...

Someone else can chime in and correct me here, but I haven't seen the OO-like access that you demonstrated here in any of the Elixir code I've seen.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top