desmond

desmond

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?

Showing Posts 1 to 8

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.

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.

desmond

desmond OP

The problem with using a Protocol is I want to be able to support different versions of the serializer for the same object, so GameSerializer.V1.serialize/1 and GameSerializer.V2.serialize/1, with the caller selecting which one to use. So I can’t just call a generic Serializer.serialize/1 without knowing what I’m passing in (list, nil, actual object) which I believe rules out the use of a single protocol. Unless I’m missing something?

OvermindDL1

OvermindDL1

How do you determine the version?

desmond

desmond OP

The controller itself calls either the V1 or V2 serializer, since the controller/route is namespaced with versions as well. So basically hardcoded.

OvermindDL1

OvermindDL1

Why not encode that into the dispatch argument then? :slight_smile:

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

Or use my ProtocolEx to dispatch on both the version and value.

There are even more things you can do. :slight_smile:

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.

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. ^.^

— All posts loaded —

Where Next? Top

Trending in Questions Top

stjefim
Hello! Suppose you are building workflow (order / task / payment) processing system with the following requirements: Each workflow con...
New
jonnycharles
I’m in search of an Elixir library that offers PDF generation capabilities similar to Ruby’s Prawn. While there have been discussions abo...
New
spammy
I’m looking to build a personal workflow to quickly deploy web applications written in elixir/phoenix, for local consumption (ie not on t...
New
Blokh
Hey guys, I’ve got a huge CSV ( around 10 GB ) that needs to be processed hourly Do you guys have any suggestions what is the best prac...
New
dli
Before I dive in myself, did anyone successfully sprinkle Hologram into their existing LiveView app? Looking for hints regarding: Addi...
New
roeland
Kia ora, We have been using elixir-google-api to connect to Google Drive. However, with the updates to Tesla due to CVEs this is now bro...
New
bottlenecked
Hi all, I wanted to ask how the community is dealing with post-release steps. Today we have Ecto migrations, which make sure that the db...
New

Other Trending Topics Top

JesseHerrick
Hey, I’m Jesse and I’m the main contributor behind Dexter, a full-featured, lightning-fast Elixir LSP optimized for large codebases. It s...
New
jimsynz
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
mcass19
ExRatatui lets you cook up rich terminal UIs in Elixir, powered by Rust’s ratatui via Rustler NIFs. Build interactive terminal applicatio...
New
netoum
Corex is an accessible, unstyled UI component library for Phoenix that integrates Zag.js state machines using Vanilla JavaScript and Live...
New
Damirados
Hello everyone. After busy few months I am happy to announce v0.1.0 of Emerge & Solve. They are GUI (Emerge) and State management (S...
New
ausimian
Emily is an Elixir library that runs Nx computations on Apple’s MLX. Install it as the default Nx backend and Nx, defn, Axon, Nx.Serving,...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews