desmond

desmond

Multiple callbacks for same function, different arguments

My application has many serializers for turning structs into something suitable for clients. These serializers have many serialize/1 functions defined to handle the nil case, list case, and finally the struct itself:

defmodule MyApp.ItemSerializer do
  def serialize(nil), do: nil
  def serialize(items) when is_list(items) do
    Enum.map(items, serialize/1)
  end

  def serialize(item) do
    %{
          # ...
        }
  end
end

I’d like to have a @behaviour MyApp.Serializer directive to guarantee that individual implementations follow the contract of implementing all the serialize/1 functions. The problem is, it looks like callbacks only respect one function implementation, and creating many callbacks with the same function name but different typespecs does not help.

Is this the expected --ahem-- behavior of callbacks?

Most Liked

NobbZ

NobbZ

Why don’t you make it a protocoll? Then you could implement the list-case once in a defimpl X, for: List, the nil in defimpl X, for: Atom, while having discrete defimpl X, for: Y for your different structs.

michalmuskala

michalmuskala

Here’s an idea - use a protocol with two callbacks - serialize_v1 and serialize_v2. For implementations where those are close enough or even the same, it’s pretty easy to delegate to a common implementation.

tty

tty

This is linked to how functions are differentiated in the BEAM. Functions are differentiated by the module they reside in, their name and arity (number of arguments the function accepts). As such serialize/1 is the same function and the various function clauses a contraction of an if-else.

If having these 3 cases are import the define the 3 different functions in the behaviour individually e.g. serialize_nil/1, serialize_lists/1, serialize_item/1. The behaviour can auto-generate a serialize/1 which calls the relevant callbacks.

If you have many different structs perhaps look into using Protocols.

Last Post!

OvermindDL1

OvermindDL1

Or use a protocol per version that can delegate to the lower version for the parts that are the same.

Yep, precisely my second suggestion. ^.^

Where Next?

Popular in Questions Top

Qqwy
Original source of discussion: This topic on the Pragmatic Programmers’ Functional Web Development with Elixir, OTP, and Phoenix forum. ...
New
hariharasudhan94
lets say i have a sample like a = 20; b = 10; if (a > b) do {:ok, "a"} end if (a < b) do {:ok, b} end if (a == b) do {:ok, "equa...
New
PeterCarter
There are pre-rolled solutions for other frameworks that do work. However, Phoenix does not seem to have these. Have people had good expe...
New
aalberti333
As the title describes, I’m trying to run Enum.map() over a list of key/value pairs, where the value is a map. My data looks like this: ...
New
vrod
I am using the Starship cross-shell prompt – it seems pretty nice, but I get some errors: [WARN] - (starship::utils): Executing command ...
New
fayddelight
I tried installing elixir 1.11.2 erlang 23.3.4 via asdf in my zsh shell. Enabled the versions locally and globally. When I list them ...
New
jason.o
In the code below, if the create action is not set to accept “extra_key” as an input, it errors out with a message shown above. Is there ...
New

Other popular topics Top

nobody
Hi! In PHP: $_SERVER[‘SERVER_ADDR’] - in Elixir? Searched the docs for ip address and the web, no good results. Thanks!
New
vonH
When I run the Plug and I recompile I wind up having to use Ctrl C to quit iex and start again. Witht the help of rlwrap I can use the cu...
New
jononomo
For some reason my phoenix channels are working for me in my local dev environment, but as soon as I deploy via Docker, I get a 403 error...
New
chrismccord
Phoenix 1.4.0 released Phoenix 1.4 is out! This release ships with exciting new features, most notably with HTTP2 support, improved deve...
688 31525 112
New
saif
Hello everyone, Long time lurker first time poster here. I’ve recently begun working on Elixir full-time again! :raised_hands: It’s been...
New
Patoshizzle
After calling mix ecto.create I get this error: 17:00:32.162 [error] GenServer #PID<0.412.0> terminating ** (Postgrex.Error) FATAL...
New

We're in Beta

About us Mission Statement