slashmili
Design a library with async callbacks
I have a question about code design in Elixir.
I’m writing a library that works with bluetooth and I want to make it general so developers can customize based on their own use case .
An example behaviour is when a new device is discovered, I want to notify the user’s code that a new device is discovered.
So I have few approaches but I’m not happy with any of them.
1: using message passing between processes
defmodule Bluetooth do
def start_discovery(handler_pid) do
#....
#eventually will send a message to `handler_pid` when a device is discovered
#ex: send(handler_pid, {:device_discovered, device})
:ok
end
end
This looks fine if only I could have a behaviour like this
defmodule BluetoothDiscovery do
@callback handle_info({:device_discovered, any}, any) :: any
end
This way users that implement the code explicitly know to implement this function.
I can technically use this but looks weird and compiler won’t complain about missing function if I have another handle_info in my module for example:
defmodule MyBluetoothDiscovery do
use GenServer
@behaviour BluetoothDiscovery
def handle_info(:timeout, state) do
end
end
2: using function callbacks
defmodule Bluetooth do
def start_discovery(handler_module) do
#....
#eventually will call device_discovered function on handler_module
#ex: apply(handler_module, :device_discovered, [device])
:ok
end
end
Now I can define a behaviour and ask users to implement it
defmodule BluetoothDiscovery do
@callback device_discovered(device) :: atom
end
This time the compiler gives me warning if I missed the implementation
defmodule MyBluetoothDiscovery do
use GenServer
@behaviour BluetoothDiscovery
def device_discovered(device) do
#handle new device
end
end
This also looks fine but reminds me of interfaces in OOP land.
Do you have any suggestion?
Most Liked
OvermindDL1
What I do is:
- If the user should always handle the callback in their own process so they cannot screw up ‘my’ process in any way (like exceptioning and such) or if they might take a while, then send a message.
- If the user is generally fast or just want them to handle it inline, faster, or let them send their own message then I use a behaviour.
![]()
Popular in Questions
Other popular topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #websockets
- #supervisor
- #advent-of-code
- #elixirconf-us
- #distillery
- #processes
- #forms
- #api
- #metaprogramming
- #security
- #performance








