Question

I wanted to write something like ((IStringer)object).ToString() (in C#) in Erlang. After some studying I've learnt that Elixir has something called Protocols that pretty much resembles the same thing of C# (in an inside-out manner). Then I came up with this idea/code in Erlang - which is nice enough to me like:

?stringer(my_val):to_string().

And it either returns the expected value or not_implemented atom!

But 2 questions:

1 - Why nobody use this or promote things based on stateful modules in Erlang? (OTP aside and from talking to some Erlangers they did not know that actually OTP is built around this! So really there is a need to change how Erlang is being taught and promoted. It's possible that I am confused.).

2 - Why I get this warning? That call actually can never fails.

The warning:

stringer.erl:18: Warning: invalid module and/or function name; this call will always fail
stringer.erl:19: Warning: invalid module and/or function name; this call will always fail
stringer.erl:20: Warning: invalid module and/or function name; this call will always fail

The code:

-module(stringer).
-export([to_string/1,sample/0]).

-define(stringer(V), {stringer, V}).

to_string({stringer, V}) when is_list(V) ->
    to_string(V, nop);
to_string({stringer, V}) when is_atom(V) ->
    to_string(V, nop);
to_string({stringer, _V}) ->
    not_implemented.

to_string(V, _Nop) ->
    Buffer = io_lib:format("~p",[V]),
    lists:flatten(Buffer).

sample() ->
    io:format("~p~n", [?stringer([1,2]):to_string()]),
    io:format("~p~n", [?stringer(cute_atom):to_string()]),
    io:format("~p~n", [?stringer(13):to_string()]).

And the output is:

"[1,2]"
"cute_atom"
not_implemented

I am doing this on Erlang R16 B2 (V5.10.3) 32 bit on Windows 8 64 bit.

Was it helpful?

Solution

The warning you see is an Erlang bug. If Erlang sees you are invoking a function in a literal tuple, it shows the warning. I have seen this while working with Elixir, I have silenced it in Elixir's compiler but forgot to report it to the Erlang team as a bug. Sorry.

The stateful module thing is actually avoided in Erlang by the majority of developers. They were added to support a feature called "parameterized modules", which has then since been removed, but the underlying dispatching mechanism still exists. If you search the Erlang Questions mailing list you can find plenty of discussion on the topic. Note that protocols in Elixir are not implemented like that though.

In fact, it seems your implementation does not seem to add anything compared to a regular function. For example, you could have simply written:

to_string(V) when is_list(V); is_atom(V) ->
  Buffer = io_lib:format("~p",[V]),
  lists:flatten(Buffer);
to_string(V) ->
  not_implemented.

and called the function directly. Your implementation is simply using the classic ad-hoc polymorphism provided by Erlang at the end of the day. The limitation of this approach is that, since dispatch is hardcoded to ?stringer, the only way to extend the to_string/1 behaviour to work with a new data type is to reimplement and replace the whole stringer module.

Here is an example of an issue that helps you ponder about this: if application A defines a "protocol" named stringer, how can applications B and C extend this protocol to their own data types and all be used by application D without loss of functionality?

In very simple words, the way protocols work in Elixir is by making the stringer module an intermediate dispatch module. So the stringer module actually works like this:

to_string(V) when is_list(V) ->
  string_list:to_string(V);
to_string(A) when is_atom(A) ->
  string_atom:to_string(A);
%% ...
to_string(A) when is_tuple(A) ->
  string_tuple:to_string(A).

and imagine that code is wrapped around something that checks if the module exists and fails accordingly if not. Of course, all of that is defined automatically for you by simply defining the protocol. There is also a mechanism (called consolidation) to compile protocols down to a fast dispatch mechanism on releases.

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