One of the features added to Elixir early on to help integration with Erlang code was the idea of overridable function definitions. This is what allowed our GenServer definition to be as simple as:
defmodule MyServer do
use GenServer
end
Implementation-wise, use GenServer defines functions such as:
def terminate(reason, state) do
:ok
end
and then mark them as overridable:
defoverridable terminate: 2
In some cases, the use of defoverridable seems to be unnecessary. For instance, we provide a default implementation for handle_call/3 and mark it as overridable, but the default implementation simply raises when invoked. That's counter-intuitive as it would be best to simply not define a default implementation in the first place, truly making the handle_call/3 callback optional.
Luckily, Erlang 18 added support for marking callbacks as optional, which we support on Elixir v1.4. We propose Elixir and libraries to leverage this feature and no longer define default implementations for the handle_* functions and instead mark them as optional.
Instead of the version we have today:
defmodule GenServer do
@callback handle_call(message, from, state)
defmacro __using__(_) do
quote do
@behaviour GenServer
def handle_call(_message, _from, _state) do
raise "handle_call/3 not implemented"
end
# ...
defoverridable handle_call: 3
end
end
end
We propose:
defmodule GenServer do
@callback handle_call(message, from, state)
@optional_callbacks handle_call: 3
defmacro __using__(_) do
quote do
@behaviour GenServer
# ...
end
end
end
The proposed code is much simpler conceptually since we are using the @optional_callbacks feature instead of defoverridable to correctly mark optional callbacks as optional. defoverridable will still be used for functions such as terminate/2, which are truly required.
We should take account of backwards compatibility, as users may be calling super in their current GenServer implementations.
This depends on #5676.
One of the features added to Elixir early on to help integration with Erlang code was the idea of overridable function definitions. This is what allowed our GenServer definition to be as simple as:
Implementation-wise,
use GenServerdefines functions such as:and then mark them as overridable:
In some cases, the use of defoverridable seems to be unnecessary. For instance, we provide a default implementation for
handle_call/3and mark it as overridable, but the default implementation simply raises when invoked. That's counter-intuitive as it would be best to simply not define a default implementation in the first place, truly making thehandle_call/3callback optional.Luckily, Erlang 18 added support for marking callbacks as optional, which we support on Elixir v1.4. We propose Elixir and libraries to leverage this feature and no longer define default implementations for the
handle_*functions and instead mark them as optional.Instead of the version we have today:
We propose:
The proposed code is much simpler conceptually since we are using the
@optional_callbacksfeature instead ofdefoverridableto correctly mark optional callbacks as optional.defoverridablewill still be used for functions such asterminate/2, which are truly required.We should take account of backwards compatibility, as users may be calling
superin their current GenServer implementations.This depends on #5676.